c - ssl_read(ssl, buffer, sizeof(buffer)) 没有正确读取json返回

标签 c json openssl

我正在使用嵌入式 linux、C 和 openSSL。我正在使用 GET 访问我的 REST 服务器并期待 json 对象响应。服务器获取到正确的 REST Get 并正确处理。但是,出于某种原因,bytes = ssl_read() 没有正确接收 json 对象。我知道服务器正在发送正确的 json 对象,因为我可以使用 Postman 或 Curl 脚本访问服务器并获得正确的 json 对象。此外,记录器(调试)显示服务器正在使用正确的 json 对象正确响应。如果我修改服务器端点代码以用字符串响应并返回 jsonObject.ToString() 我确实得到了正确的响应,但它是一个字符串。为什么我没有得到一个好的 json 对象?这是一个简短的代码 list ,

 // 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 Body:只有2个字符,总是数字,Buffer Length是4个字节。真正的json对象是这样的,

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

正如我所说,这段代码工作正常,除了它没有获得存储在缓冲区中的正确 json 对象。有问题的 ssl_read() 位于 list 的末尾并标记为 <=== **** Error is Here ****。有什么想法吗?

最佳答案

您需要阅读“分块”传输编码,它不仅仅是纯文本。您请求 sizeof(buffer),但正确的方法是阅读,直到您找到来自服务器的单行文本形式的 0(到目前为止正如我所记得的那样)意味着 block 是完整的。

我为我现在正在进行的项目创建了一个简单的 HTTP 库。我首先分析 HTTP header 主要对 3 件事感兴趣

  1. Content-Length header :如果存在,只需获取值并在单个read 中从服务器读取它,尽管这意味着读取循环OpenSSL 没那么简单。

  2. Transfer-Encoding header :如果内容长度不存在,您可以在这里确定如何读取数据。

  3. Content-Encoding header :用于确定内容是否已压缩,例如 gzip

在我的特殊情况下,这就足够了。但这只是协议(protocol)的一小部分,并不适用于一般情况。虽然,也许它对您有用。

所以需要先从服务器获取所有的header,逐行读取直到出现空行。获得 header 后,您可以使用这些信息来决定如何阅读响应正文。基本上,您想要实现一个简单的 HTTP 客户端,为此至少应该实现 HTTP 协议(protocol)的最基本的东西。

工作量很大,我想如果你能安装 OpenSSL,你很可能可以使用 libcurl 但我不确定,因为我从未使用过嵌入式 linux。

注意:如果您了解如何 字符串有效,你不会像那样使用 strcat()

关于c - ssl_read(ssl, buffer, sizeof(buffer)) 没有正确读取json返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38469391/

相关文章:

c - 用 C 编写 Telnet 服务器和 Telnet 客户端

iphone - Json XCode获取数据

java - 415 当请求正文具有以自定义对象为键的 Map 时,出现不支持的对象异常

c - 用于 RSA 的 OpenSSL : undefined reference to RSA_new

c - OpenSSL 无法在后端加载证书

c - 解析缺少条目的 csv 文件

计算 UNIX 进程时间溢出之前还有多少天

c++ - SSL 握手产生 BIO 错误

c - Couchbase 在多大程度上可以替代 Memcached

ios - 在 Swift 中将数组转换为 Alamofire 参数