HttpResponse* http_response_recv(rdpTls* tls) { wStream* s; int size; int count; int status; int position; char* line; char* buffer; char* header; char* payload; int bodyLength; int payloadOffset; HttpResponse* response; size = 1024; payload = NULL; payloadOffset = 0; s = Stream_New(NULL, size); if (!s) goto out_free; buffer = (char*) Stream_Buffer(s); response = http_response_new(); if (!response) goto out_free; response->ContentLength = 0; while (TRUE) { while (!payloadOffset) { status = BIO_read(tls->bio, Stream_Pointer(s), Stream_Capacity(s) - Stream_GetPosition(s)); if (status <= 0) { if (!BIO_should_retry(tls->bio)) goto out_error; USleep(100); continue; } #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(Stream_Pointer(s), status); #endif Stream_Seek(s, status); if (Stream_GetRemainingLength(s) < 1024) { Stream_EnsureRemainingCapacity(s, 1024); buffer = (char*) Stream_Buffer(s); payload = &buffer[payloadOffset]; } position = Stream_GetPosition(s); if (position >= 4) { line = string_strnstr(buffer, "\r\n\r\n", position); if (line) { payloadOffset = (line - buffer) + 4; payload = &buffer[payloadOffset]; } } } if (payloadOffset) { count = 0; line = buffer; position = Stream_GetPosition(s); while ((line = string_strnstr(line, "\r\n", payloadOffset - (line - buffer) - 2))) { line += 2; count++; } response->count = count; if (count) { response->lines = (char**) calloc(response->count, sizeof(char*)); if (!response->lines) goto out_error; } header = (char*) malloc(payloadOffset); if (!header) goto out_error; CopyMemory(header, buffer, payloadOffset); header[payloadOffset - 1] = '\0'; header[payloadOffset - 2] = '\0'; count = 0; line = strtok(header, "\r\n"); while (line && response->lines) { response->lines[count] = _strdup(line); if (!response->lines[count]) goto out_error; line = strtok(NULL, "\r\n"); count++; } free(header); if (!http_response_parse_header(response)) goto out_error; response->BodyLength = Stream_GetPosition(s) - payloadOffset; if (response->BodyLength > 0) { response->BodyContent = (BYTE*) malloc(response->BodyLength); if (!response->BodyContent) goto out_error; CopyMemory(response->BodyContent, payload, response->BodyLength); } bodyLength = 0; /* expected body length */ if (response->ContentType) { if (_stricmp(response->ContentType, "text/plain") == 0) { bodyLength = response->ContentLength; } } if (bodyLength != response->BodyLength) { WLog_WARN(TAG, "http_response_recv: %s unexpected body length: actual: %d, expected: %d", response->ContentType, response->ContentLength, response->BodyLength); } break; } if (Stream_GetRemainingLength(s) < 1024) { Stream_EnsureRemainingCapacity(s, 1024); buffer = (char*) Stream_Buffer(s); payload = &buffer[payloadOffset]; } } Stream_Free(s, TRUE); return response; out_error: http_response_free(response); out_free: Stream_Free(s, TRUE); return NULL; }
HttpResponse* http_response_recv(rdpTls* tls, BOOL readContentLength) { size_t size; size_t position; size_t bodyLength = 0; size_t payloadOffset; HttpResponse* response; size = 2048; payloadOffset = 0; response = http_response_new(); if (!response) return NULL; response->ContentLength = 0; while (payloadOffset == 0) { size_t s; char* end; /* Read until we encounter \r\n\r\n */ int status = BIO_read(tls->bio, Stream_Pointer(response->data), 1); if (status <= 0) { if (!BIO_should_retry(tls->bio)) { WLog_ERR(TAG, "%s: Retries exceeded", __FUNCTION__); ERR_print_errors_cb(print_bio_error, NULL); goto out_error; } USleep(100); continue; } #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(Stream_Pointer(response->data), status); #endif Stream_Seek(response->data, (size_t)status); if (!Stream_EnsureRemainingCapacity(response->data, 1024)) goto out_error; position = Stream_GetPosition(response->data); if (position < 4) continue; else if (position > RESPONSE_SIZE_LIMIT) { WLog_ERR(TAG, "Request header too large! (%"PRIdz" bytes) Aborting!", bodyLength); goto out_error; } /* Always check at most the lase 8 bytes for occurance of the desired * sequence of \r\n\r\n */ s = (position > 8) ? 8 : position; end = (char*)Stream_Pointer(response->data) - s; if (string_strnstr(end, "\r\n\r\n", s) != NULL) payloadOffset = Stream_GetPosition(response->data); } if (payloadOffset) { size_t count = 0; char* buffer = (char*)Stream_Buffer(response->data); char* line = (char*) Stream_Buffer(response->data); while ((line = string_strnstr(line, "\r\n", payloadOffset - (line - buffer) - 2UL))) { line += 2; count++; } response->count = count; if (count) { response->lines = (char**) calloc(response->count, sizeof(char*)); if (!response->lines) goto out_error; } buffer[payloadOffset - 1] = '\0'; buffer[payloadOffset - 2] = '\0'; count = 0; line = strtok(buffer, "\r\n"); while (line && (response->count > count)) { response->lines[count] = line; line = strtok(NULL, "\r\n"); count++; } if (!http_response_parse_header(response)) goto out_error; response->BodyLength = Stream_GetPosition(response->data) - payloadOffset; bodyLength = response->BodyLength; /* expected body length */ if (readContentLength) { const char* cur = response->ContentType; while (cur != NULL) { if (http_use_content_length(cur)) { if (response->ContentLength < RESPONSE_SIZE_LIMIT) bodyLength = response->ContentLength; break; } cur = strchr(cur, ';'); } } if (bodyLength > RESPONSE_SIZE_LIMIT) { WLog_ERR(TAG, "Expected request body too large! (%"PRIdz" bytes) Aborting!", bodyLength); goto out_error; } /* Fetch remaining body! */ while (response->BodyLength < bodyLength) { int status; if (!Stream_EnsureRemainingCapacity(response->data, bodyLength - response->BodyLength)) goto out_error; status = BIO_read(tls->bio, Stream_Pointer(response->data), bodyLength - response->BodyLength); if (status <= 0) { if (!BIO_should_retry(tls->bio)) { WLog_ERR(TAG, "%s: Retries exceeded", __FUNCTION__); ERR_print_errors_cb(print_bio_error, NULL); goto out_error; } USleep(100); continue; } Stream_Seek(response->data, (size_t)status); response->BodyLength += (unsigned long)status; if (response->BodyLength > RESPONSE_SIZE_LIMIT) { WLog_ERR(TAG, "Request body too large! (%"PRIdz" bytes) Aborting!", response->BodyLength); goto out_error; } } if (response->BodyLength > 0) response->BodyContent = &(Stream_Buffer(response->data))[payloadOffset]; if (bodyLength != response->BodyLength) { WLog_WARN(TAG, "%s: %s unexpected body length: actual: %d, expected: %d", __FUNCTION__, response->ContentType, response->BodyLength, bodyLength); if (bodyLength > 0) response->BodyLength = MIN(bodyLength, response->BodyLength); } } return response; out_error: http_response_free(response); return NULL; }