예제 #1
0
HttpResponse* http_response_recv(rdpTls* tls)
{
    BYTE* p;
    int nbytes;
    int length;
    int status;
    BYTE* buffer;
    char* content;
    char* header_end;
    HttpResponse* http_response;
    nbytes = 0;
    length = 10000;
    content = NULL;

    buffer = calloc(length, 1);

    if (!buffer)
        return NULL;

    http_response = http_response_new();

    if (!http_response)
        goto out_free;

    p = buffer;
    http_response->ContentLength = 0;

    while (TRUE)
    {
        while (nbytes < 5)
        {
            status = BIO_read(tls->bio, p, length - nbytes);

            if (status <= 0)
            {
                if (!BIO_should_retry(tls->bio))
                    goto out_error;

                USleep(100);
                continue;
            }

#ifdef HAVE_VALGRIND_MEMCHECK_H
            VALGRIND_MAKE_MEM_DEFINED(p, status);
#endif
            nbytes += status;
            p = (BYTE*) &buffer[nbytes];
        }

        header_end = strstr((char*) buffer, "\r\n\r\n");

        if (!header_end)
        {
            WLog_ERR(TAG, "invalid response:");
            winpr_HexDump(TAG, WLOG_ERROR, buffer, status);
            goto out_error;
        }

        header_end += 2;

        if (header_end != NULL)
        {
            int count;
            char* line;
            header_end[0] = '\0';
            header_end[1] = '\0';
            content = header_end + 2;
            count = 0;
            line = (char*) buffer;

            while ((line = strstr(line, "\r\n")) != NULL)
            {
                line++;
                count++;
            }

            http_response->count = count;

            if (count)
            {
                http_response->lines = (char**) calloc(http_response->count, sizeof(char*));

                if (!http_response->lines)
                    goto out_error;
            }

            count = 0;
            line = strtok((char*) buffer, "\r\n");

            while ((line != NULL) && http_response->lines)
            {
                http_response->lines[count] = _strdup(line);

                if (!http_response->lines[count])
                    goto out_error;

                line = strtok(NULL, "\r\n");
                count++;
            }

            if (!http_response_parse_header(http_response))
                goto out_error;

            http_response->bodyLen = nbytes - (content - (char*)buffer);

            if (http_response->bodyLen > 0)
            {
                http_response->BodyContent = (BYTE*) malloc(http_response->bodyLen);

                if (!http_response->BodyContent)
                    goto out_error;

                CopyMemory(http_response->BodyContent, content, http_response->bodyLen);
            }

            break;
        }

        if ((length - nbytes) <= 0)
        {
            length *= 2;
            buffer = realloc(buffer, length);
            p = (BYTE*) &buffer[nbytes];
        }
    }

    free(buffer);
    return http_response;
out_error:
    http_response_free(http_response);
out_free:
    free(buffer);
    return NULL;
}
예제 #2
0
파일: http.c 프로젝트: lemonmojo/FreeRDP
HttpResponse* http_response_recv(rdpTls* tls)
{
	BYTE* p;
	int nbytes;
	int length;
	int status;
	BYTE* buffer;
	char* content;
	char* header_end;
	HttpResponse* http_response;

	nbytes = 0;
	length = 10000;
	content = NULL;
	buffer = malloc(length);
	if (!buffer)
		return NULL;

	http_response = http_response_new();
	if (!http_response)
		goto out_free;

	p = buffer;
	http_response->ContentLength = 0;

	while (TRUE)
	{
		while (nbytes < 5)
		{
			status = tls_read(tls, p, length - nbytes);
            
			if (status < 0)
				goto out_error;

			if (!status)
				continue;

			nbytes += status;
			p = (BYTE*) &buffer[nbytes];
		}

		header_end = strstr((char*) buffer, "\r\n\r\n");
        
		if (!header_end)
		{
			fprintf(stderr, "http_response_recv: invalid response:\n");
			winpr_HexDump(buffer, status);
			goto out_error;
		}

		header_end += 2;

		if (header_end != NULL)
		{
			int count;
			char* line;

			header_end[0] = '\0';
			header_end[1] = '\0';
			content = &header_end[2];

			count = 0;
			line = (char*) buffer;

			while ((line = strstr(line, "\r\n")) != NULL)
			{
				line++;
				count++;
			}

			http_response->count = count;
			if (count)
			{
				http_response->lines = (char **)calloc(http_response->count, sizeof(char *));
				if (!http_response->lines)
					goto out_error;
			}

			count = 0;
			line = strtok((char*) buffer, "\r\n");

			while (line != NULL)
			{
				http_response->lines[count] = _strdup(line);
				if (!http_response->lines[count])
					goto out_error;

				line = strtok(NULL, "\r\n");
				count++;
			}

			if (!http_response_parse_header(http_response))
				goto out_error;

			if (http_response->ContentLength > 0)
			{
				http_response->Content = _strdup(content);
				if (!http_response->Content)
					goto out_error;
			}

			break;
		}

		if ((length - nbytes) <= 0)
		{
			length *= 2;
			buffer = realloc(buffer, length);
			p = (BYTE*) &buffer[nbytes];
		}
	}

	free(buffer);

	return http_response;

out_error:
	http_response_free(http_response);
out_free:
	free(buffer);
	return NULL;
}
예제 #3
0
/* Do a GET, HEAD, or POST transaction. */
static int do_transaction(struct http_request *request,
    struct socket_buffer *client_sock, struct socket_buffer *server_sock)
{
    char buf[BUFSIZ];
    struct http_response response;
    char *line;
    char *request_str, *response_str;
    size_t len;
    int code, n;

    /* We don't handle the chunked transfer encoding, which in the absence of a
       Content-Length is the only way we know the end of a request body. RFC
       2616, section 4.4 says, "If a request contains a message-body and a
       Content-Length is not given, the server SHOULD respond with 400 (bad
       request) if it cannot determine the length of the message, or with 411
       (length required) if it wishes to insist on receiving a valid
       Content-Length." */
    if (strcmp(request->method, "POST") == 0 && request->content_length == 0) {
        if (o.debug)
            logdebug("POST request with no Content-Length.\n");
        return 400;
    }

    /* The version we use to talk to the server. */
    request->version = HTTP_10;

    /* Remove headers that only apply to our connection with the client. */
    code = http_header_remove_hop_by_hop(&request->header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    /* Build the Host header. */
    if (request->uri.port == -1 || request->uri.port == 80)
        n = Snprintf(buf, sizeof(buf), "%s", request->uri.host);
    else
        n = Snprintf(buf, sizeof(buf), "%s:%hu", request->uri.host, request->uri.port);
    if (n < 0 || n >= sizeof(buf)) {
        /* Request Entity Too Large. */
        return 501;
    }
    request->header = http_header_set(request->header, "Host", buf);

    request->header = http_header_set(request->header, "Connection", "close");

    /* Send the request to the server. */
    request_str = http_request_to_string(request, &len);
    n = send(server_sock->fdn.fd, request_str, len, 0);
    free(request_str);
    if (n < 0)
        return 504;
    /* Send the request body, if any. Count up to Content-Length. */
    while (request->bytes_transferred < request->content_length) {
        n = socket_buffer_read(client_sock, buf, MIN(sizeof(buf), request->content_length - request->bytes_transferred));
        if (n < 0)
            return 504;
        if (n == 0)
            break;
        request->bytes_transferred += n;
        n = send(server_sock->fdn.fd, buf, n, 0);
        if (n < 0)
            return 504;
    }
    if (o.debug && request->bytes_transferred < request->content_length)
        logdebug("Received only %lu request body bytes (Content-Length was %lu).\n", request->bytes_transferred, request->content_length);


    /* Read the response. */
    code = http_read_status_line(server_sock, &line);
    if (o.debug > 1)
        logdebug("Status-Line: %s", line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading Status-Line.\n");
        return 0;
    }
    code = http_parse_status_line(line, &response);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing Status-Line.\n");
        return 0;
    }

    code = http_read_header(server_sock, &line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading header.\n");
        return 0;
    }
    if (o.debug > 1)
        logdebug("Response header:\n%s", line);

    code = http_response_parse_header(&response, line);
    free(line);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing response header.\n");
        return 0;
    }


    /* The version we use to talk to the client. */
    response.version = HTTP_10;

    /* Remove headers that only apply to our connection with the server. */
    code = http_header_remove_hop_by_hop(&response.header);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error removing hop-by-hop headers.\n");
        return code;
    }

    response.header = http_header_set(response.header, "Connection", "close");

    /* Send the response to the client. */
    response_str = http_response_to_string(&response, &len);
    n = fdinfo_send(&client_sock->fdn, response_str, len);
    free(response_str);
    if (n < 0) {
        http_response_free(&response);
        return 504;
    }
    /* If the Content-Length is 0, read until the connection is closed.
       Otherwise read until the Content-Length. At this point it's too late to
       return our own error code so return 0 in case of any error. */
    while (response.content_length == 0
        || response.bytes_transferred < response.content_length) {
        size_t remaining = response.content_length - response.bytes_transferred;
        size_t count;

        count = sizeof(buf);
        if (response.content_length > 0 && remaining < count)
            count = remaining;
        n = socket_buffer_read(server_sock, buf, count);
        if (n <= 0)
            break;
        response.bytes_transferred += n;
        n = fdinfo_send(&client_sock->fdn, buf, n);
        if (n < 0)
            break;
    }

    http_response_free(&response);

    return 0;
}
예제 #4
0
파일: http.c 프로젝트: mattymo/FreeRDP
HttpResponse* http_response_recv(rdpTls* tls)
{
	uint8* p;
	int nbytes;
	int length;
	int status;
	uint8* buffer;
	char* content;
	char* header_end;
	HttpResponse* http_response;

	nbytes = 0;
	length = 0xFFFF;
	buffer = xmalloc(length);
	http_response = http_response_new();

	p = buffer;

	while (true)
	{
		status = tls_read(tls, p, length - nbytes);

		if (status > 0)
		{
			nbytes += status;
			p = (uint8*) &buffer[nbytes];
		}
		else if (status == 0)
		{
			continue;
		}
		else
		{
			return NULL;
			break;
		}

		header_end = strstr((char*) buffer, "\r\n\r\n") + 2;

		if (header_end != NULL)
		{
			int count;
			char* line;

			header_end[0] = '\0';
			header_end[1] = '\0';
			content = &header_end[2];

			count = 0;
			line = (char*) buffer;

			while ((line = strstr(line, "\r\n")) != NULL)
			{
				line++;
				count++;
			}

			http_response->count = count;
			http_response->lines = (char**) xmalloc(sizeof(char*) * http_response->count);

			count = 0;
			line = strtok((char*) buffer, "\r\n");

			while (line != NULL)
			{
				http_response->lines[count] = xstrdup(line);
				line = strtok(NULL, "\r\n");
				count++;
			}

			http_response_parse_header(http_response);

			if (http_response->ContentLength > 0)
			{
				http_response->Content = xstrdup(content);
			}

			break;
		}

		if ((length - nbytes) <= 0)
		{
			length *= 2;
			buffer = xrealloc(buffer, length);
			p = (uint8*) &buffer[nbytes];
		}
	}

	return http_response;
}
예제 #5
0
파일: http.c 프로젝트: matthew-n/FreeRDP
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;
}
예제 #6
0
파일: http.c 프로젝트: FreeRDP/FreeRDP
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;
}