2016-07-19 3 views
1

Я работаю со встроенными linux, C и openSSL. Я удаляю свой сервер REST с помощью GET и ожидаю ответа на json-объект. Сервер получает правильный REST Get и обрабатывает его правильно. Однако по какой-то причине байты = ssl_read() неправильно получают объект json. Я знаю, что сервер отправляет правильный json-объект, потому что я могу поразить сервер скриптом Postman или Curl, и я получаю правильный объект json. Кроме того, журнал (отладка) показывает, что сервер правильно отвечает правильным объектом json. Если я модифицирую код конечной точки сервера, чтобы ответить строкой и вернуть jsonObject.ToString(), я получаю правильный ответ, но это строка. Почему я не получаю хороший объект json? Вот сокращенный код листинга,ssl_read (ssl, buffer, sizeof (buffer)) не читает json return правильно

// Define some parameters 
int sockfd, bytes_read; 
struct sockaddr_in dest; 
struct hostent *hostent; 
unsigned short svrport = 8443; 

char hdr[4000]; 
char buffer[4000]; 

// Initialise Crypto library 
ERR_load_crypto_strings(); 
OpenSSL_add_all_algorithms(); 
OPENSSL_config(NULL); 

// Create GET status HTTP Client Message String 
bzero(hdr, sizeof(hdr)); 
strcpy(hdr, "GET /status HTTP/1.1\r\n"); 
strcat(hdr, "Host: xxx.xxx.xxx.xxx\r\n"); 
strcat(hdr, "X-BMID-ID: 1234-5678\r\n"); 
strcat(hdr, "Authorization: "); 
strcat(hdr, sttb64e); 
strcat(hdr, "\r\n"); 
strcat(hdr, "Accept: application/json\r\n"); 
strcat(hdr, "Content-Type: application/json\r\n"); 
strcat(hdr, "Connection: close\r\n"); 
strcat(hdr, "\r\n"); 

// Initialize server address/port struct 
bzero(&dest, sizeof(dest)); 
dest.sin_family = AF_INET; 
dest.sin_port = htons(svrport); 
dest.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx"); 

if (dest.sin_addr.s_addr == INADDR_NONE) { 
     printf("Incorrect Address Expression\n"); 
     return 0; 
} 

// Connect Socket 
if (connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0) { 
     printf("Socket Connection Failed\n"); 
     close(sockfd); 
     return 0; 
} 

// Now initialize SSL Engine 
SSL_METHOD const *method; 
SSL_CTX *ctx; 
SSL *ssl; 

SSL_library_init(); 
OpenSSL_add_ssl_algorithms(); 
SSL_load_error_strings(); 
method = TLSv1_2_client_method(); 
ctx = SSL_CTX_new(method); 
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); 

// Make sure SSL Engine is ok 
if (ctx == NULL) { 
    printf("SSL Engine initialization failed\n"); 
    ERR_print_errors_fp(stderr); 
    close(sockfd); 
    return 0; 
} 

// Now create the SSL connection state 
ssl = SSL_new(ctx); 
SSL_set_fd(ssl, sockfd); 

// Check to see if the SSL socket was connected 
if (SSL_connect(ssl) == FAIL) { 
    printf("SSL socket failed to connect\n"); 
    return 0; 
} 

// Now Send Secure Message 
bzero(buffer, sizeof(buffer)); 
SSL_write(ssl, hdr, strlen(hdr)); 
bytes = SSL_read(ssl, buffer, sizeof(buffer)); 
buffer[bytes] = 0; 
if (verbose) { 
    printf("Received Header:\n"); 
    printf("%s\n", buffer); 
} 
bzero(buffer, sizeof(buffer)); 
bytes = SSL_read(ssl, buffer, sizeof(buffer)); <=== **** Error is Here **** 
buffer[bytes] = 0; 
printf("Received Body:%s\n\n", buffer); 
printf("Buffer Length = %i\n\n", bytes); 
SSL_free(ssl); 

// Shut down connection 
close(sockfd); 
SSL_CTX_free(ctx); 

«Received Тело: только имеет 2 знака, всегда числа, а длина буфера составляет 4 байта Реальный объект JSON выглядит так,

{"status":"OK","shadowRequest":"0","serviceCount":1} 

. Как я уже сказал, этот код работает отлично, за исключением того, что он не получает правильный json-объект, хранящийся в буфере. Вопрос ssl_read() находится в конце списка и помечен < === **** Ошибка Здесь ****. Любые идеи?

+0

Что возвращает 'SSL_read'? Он может вернуть отрицательное значение при сбое, или ноль, если соединение было закрыто. Вам действительно нужно это проверить. –

+1

Мне все еще интересно, почему 'bytes = SSL_read (ssl, buffer, sizeof (buffer));' появляется * дважды * в этом списке. Довольно недоразумение с моей стороны относительно того, что вы на самом деле делаете. И fwiw, 'buffer [bytes] = 0;' довольно бессмысленно, если вы просто собираетесь «bzero» весь буфер на самой следующей строке. – WhozCraig

+0

Извините, я вырезал код. Я обновил код, поэтому первый SSL_read() имеет больше смысла. Первый SSL_read() возвращает следующее: Заголовок получателя: HTTP/1.1 200 OK Сервер: Apache-Coyote/1.1 X-Application-Context: application: 8443 Content-Type: application/json; charset = UTF -8 Transfer-Encoding: фрагментированное Дата: Tue, 19 Jul 2016 20:48:10 GMT соединения: близко - Второй SSL_read() возвращает следующее, - Полученное тело: 34 Buffer Length = 4 – skmansfield

ответ

2

Вам нужно прочитать о кодировке передачи «chu nked ", который не является простым текстом. Вы запрашиваете sizeof(buffer), но правильный способ заключается в том, чтобы прочитать, пока вы не найдете 0, который поступает с сервера в виде текста в одной строке (, насколько я помню), что означает, что chunk s завершены.

Я создал простую HTTP-библиотеку для проекта, над которым я сейчас работаю. И я анализирую заголовки HTTP первый заинтересованы в первую очередь 3 вещи

  1. Content-Length заголовок: если присутствует просто получить значение и прочитать, что с сервера в одном чтения, хотя это означает read loop с OpenSSL это не так просто.

  2. Кодирование передачи Заголовок: Здесь вы можете определить, как читать данные, если длина содержимого отсутствовала.

  3. Content-Encoding заголовка: Используется для определения, если содержание сжимается, например, с Gzip.

В моем конкретном случае этого достаточно. Но это всего лишь крошечная часть протокола, и в целом это не подходит. Хотя, возможно, это может сработать для вас.

Так что вам нужно сначала получить все заголовки с сервера, прочитать каждую строку, пока не появится пустая строка. После того, как у вас есть заголовки, вы можете использовать эту информацию, чтобы решить, как читать тело ответа. В принципе, вы хотите реализовать простой HTTP-клиент, для которого должны быть реализованы, по крайней мере, самые основные вещи протокола HTTP.

Это очень много работы, и я бы предположил, что если вы можете установить OpenSSL, очень вероятно, что вы можете использовать libcurl, но я не уверен, так как я никогда не работал со встроенным Linux.

ПРИМЕЧАНИЕ: Если вы понимаете, как работает строки, вы бы не использовать strcat() подобные.

2

Две вещи:

  1. Не претендующие HTTP/1.1 поддержку, если вы собираетесь реализовать все требования к HTTP 1.1 спецификации.

  2. Вы не можете предположить, что ваш первый звонок SSL_read доставит вам заголовки, а ваш следующий получит вас. Вы должны фактически реализовать протокол HTTP. SSL не понимает HTTP и не знает, что такое заголовок или тело или как их читать.

Честно говоря, ваш уровень знания протокола говорит о том, что вы находитесь здесь далеко от своей глубины. Вы действительно должны найти существующую реализацию HTTP-клиента, которая будет соответствовать вашим потребностям, а не пытаться сворачивать ваши собственные. Даже если это случается, чтобы работать каждый раз, когда вы его проверяете, есть замечательное количество тонких ошибок, которые можно сделать, и каждый человек, который является новым для этого, делает почти все из них.

Например:

bytes = SSL_read(ssl, buffer, sizeof(buffer)); 
buffer[bytes] = 0; 

bytes == sizeof(buffer) Что делать, если после первой линии? Вторая строка будет записываться за конец буфера.