Пример #1
0
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;
}
Пример #2
0
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;
}