Example #1
0
/*
 *
    should use evbuffer_free(evb); to free this evbuffer
 * */
static struct http_response * http_req(char * ip, int port, char * verb, char * path, char * data){

    char port_str[6];
    sprintf(port_str, "%d", port);

    int cs = client_socket(ip, port_str);
    char * request_buffer = alloca(100 + strlen(path)); // in stack do not need free
    char response_buffer[1024*8];

    sprintf(request_buffer, "%s %s HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", verb, path, strlen(data), data);
    //sprintf(request_buffer, "GET %s HTTP/1.0\r\nUser-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15\r\n\r\n", path);
    fprintf(stderr, "%s", request_buffer);

    int rst = tcptowrite(cs, request_buffer, strlen(request_buffer) , 30000);
    printf("tcptowrite rst: %d", rst);
    int readed = 0;

    struct evbuffer *evb = evbuffer_new();
    /*evbuffer_read(evb, cs, 30);*/

    while ((readed = tcptoread(cs, response_buffer, 1024*8, 30000)) > 0){
        printf("readed len: %d \n", readed);
        evbuffer_add(evb, response_buffer, readed);
    }

    struct evbuffer_ptr evbptr = evbuffer_search(evb, "\r\n\r\n", 4, NULL);

    struct evbuffer *headers = evbuffer_new();
    evbuffer_remove_buffer(evb, headers, evbptr.pos);
    /*evbuffer_drain(evb, evbptr.pos);*/
    tcpclose(cs);
    int code = parse_response_status_code(headers);
    return http_response_new(code, headers, evb);
}
Example #2
0
/*
** Send a reply indicating that the HTTP request was malformed
*/
static void 
malformed_request(int code, char *info)
{
  HttpResponse *res = NULL;

  res = http_response_new(NULL);

  http_response_set_status(res, 501, "Not Implemented");
  http_response_printf(res, 
    "<html><body>Unrecognized HTTP Request Code=%i</body></html>\n",
    code);
  http_response_send(res);
  
  /* log Error */
  syslog(LOG_LOCAL0|LOG_INFO, "Malformed request 501\nCode=%i\n%s\n", code,info);
        

  exit(0);
}
Example #3
0
static void push_http_xml_msg(struct http_thread_env *hte, XmlTag *tag)
{
	HttpResponse *resp;

	resp = http_response_new(HTTP_STATUS_OK, NULL);

	if (tag == NULL)
		tag = mbb_xml_msg_ok();

	if (hte->json)
		resp->body = xml_tag_to_json(tag);
	else
		resp->body = xml_tag_to_string_escape(tag);

	xml_tag_free(tag);
	trash_push(&resp->trash, resp->body, NULL);

	push_http_response(hte, resp);
}
Example #4
0
void webserver_send_response(ClientSocket*    client,
                             enum EHttpStatus status,
                             const char*      body,
                             const char*      content_type)
{
  // Build the Content-Length string
  char content_length[20] = {0};
  snprintf(content_length, 20, "%zu", (body ? strlen(body) : 0));
  if (!content_type) { content_type = "text/plain"; }

  // Build the response object
  HttpResponse* res = http_response_new();
  http_response_set_status(res, HTTP_VERSION_1_0, status);
  http_response_add_header(res, "Server", "webserver");
  http_response_add_header(res, "Content-Length", content_length);
  if (body) { http_response_add_header(res, "Content-Type", content_type); }
  if (body) { http_response_set_body(res, body); }

  // Send the response and clean up
  client_socket_send(client, http_response_string(res), http_response_length(res));
  http_response_free(res);
}
Example #5
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;
}
Example #6
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 = 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;
}
Example #7
0
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;
}
Example #8
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;
}
Example #9
0
int
http_response_parse(const char *data, size_t sz, uint32_t flags,
                    struct http_response **presponse, size_t *psz) {
    struct http_response *response;
    const char *ptr;
    size_t len, toklen;
    char status_string[4];
    size_t status_sz;
    int32_t status_value;
    int ret;

    ptr = data;
    len = sz;

#define HTTP_FAIL(fmt_, ...)                  \
    do {                                      \
        if (fmt_)                             \
            c_set_error(fmt_, ##__VA_ARGS__); \
        http_response_delete(response);       \
        return -1;                            \
    } while (0)

#define HTTP_TRUNCATED()                      \
    do {                                      \
        http_response_delete(response);       \
        return 0;                             \
    } while (0)

    response = http_response_new();

    /* Version */
    toklen = c_memcspn(ptr, len, " ");
    if (toklen == len) {
        if (len > HTTP_VERSION_MAX_LENGTH)
            HTTP_FAIL("invalid version");
        HTTP_TRUNCATED();
    }

    if (http_version_parse(ptr, toklen, &response->version) == -1)
        HTTP_FAIL(NULL);

    ptr += toklen + 1;
    len -= toklen + 1;

    /* Status */
    toklen = c_memcspn(ptr, len, " ");
    if (toklen == len) {
        if (len > 3)
            HTTP_FAIL("invalid status code");
        HTTP_TRUNCATED();
    }

    if (toklen > 3)
        HTTP_FAIL("invalid status code");

    memcpy(status_string, ptr, toklen);
    status_string[toklen] = '\0';

    if (c_parse_i32(status_string, &status_value, &status_sz) == -1)
        HTTP_FAIL("invalid status code");
    if (status_sz != toklen)
        HTTP_FAIL("invalid trailing data after status code");
    response->status = (enum http_status)status_value;

    ptr += toklen + 1;
    len -= toklen + 1;

    /* Reason */
    toklen = c_memcspn(ptr, len, "\r");
    if (toklen == len) {
        if (len > HTTP_REASON_MAX_LENGTH)
            HTTP_FAIL("reason string too long");
        HTTP_TRUNCATED();
    }

    response->reason = c_strndup(ptr, toklen);

    ptr += toklen;
    len -= toklen;

    /* End of status line */
    if (len < 2)
        HTTP_TRUNCATED();
    if (ptr[0] != '\r' || ptr[1] != '\n')
        HTTP_FAIL("malformed status line");

    ptr += 2;
    len -= 2;

    /* Headers */
    http_headers_delete(response->headers);
    response->headers = NULL;

    ret = http_headers_parse(ptr, len, &response->headers, NULL, &toklen);
    if (ret == -1)
        HTTP_FAIL(NULL);
    if (ret == 0)
        HTTP_TRUNCATED();

    ptr += toklen;
    len -= toklen;

    if (http_response_preprocess_headers(response) == -1) {
        http_response_delete(response);
        return -1;
    }

    /* Body */
    if (!http_response_can_have_body(response))
        goto end;

    if (response->has_content_length) {
        if (response->content_length > HTTP_RESPONSE_MAX_CONTENT_LENGTH)
            HTTP_FAIL("payload too large");

        if (len < response->content_length)
            HTTP_TRUNCATED();

        response->body_sz = response->content_length;
        response->body = c_strndup(ptr, response->content_length);

        ptr += response->body_sz;
        len -= response->body_sz;
    } else if (response->is_body_chunked) {
        struct http_headers *trailer;
        size_t chunked_data_sz;

        ret = http_chunked_data_parse(ptr, len,
                                      &response->body, &response->body_sz,
                                      &chunked_data_sz);
        if (ret == -1)
            HTTP_FAIL("invalid chunked body: %s", c_get_error());
        if (ret == 0)
            HTTP_TRUNCATED();

        ptr += chunked_data_sz;
        len -= chunked_data_sz;

        /* Trailer */
        ret = http_headers_parse(ptr, len, &trailer, NULL, &toklen);
        if (ret == -1)
            HTTP_FAIL(NULL);
        if (ret == 0)
            HTTP_TRUNCATED();

        http_headers_merge_nocopy(response->headers, trailer);
        http_headers_delete(trailer);

        ptr += toklen;
        len -= toklen;
    } else if (response->has_connection_close) {
        size_t content_length;

        if (flags & HTTP_RESPONSE_PARSE_EOF) {
            content_length = len;

            if (content_length > HTTP_RESPONSE_MAX_CONTENT_LENGTH)
                HTTP_FAIL("payload too large");

            response->body_sz = content_length;
            response->body = c_strndup(ptr, content_length);

            ptr += response->body_sz;
            len -= response->body_sz;
        } else {
            HTTP_TRUNCATED();
        }
    } else {
        HTTP_FAIL("missing content length");
    }

#undef HTTP_FAIL
#undef HTTP_TRUNCATED

end:
    *presponse = response;
    *psz = sz - len;
    return 1;
}
Example #10
0
void *handle_connection(void *arg) {
  st_netfd_t client_nfd = (st_netfd_t)arg;
  struct http_stream *s = http_stream_create(HTTP_SERVER, SEC2USEC(5));
  char buf[4*1024];
  int error = 0;
  struct http_stream *cs = NULL;
  uri_t *u = uri_new();
  int should_close = 1;
  for (;;) {
    should_close = 1;
    if (s->status != HTTP_STREAM_OK) break;
    cs = NULL;
    error = 0;
    s->timeout = SEC2USEC(5);
    int status = http_stream_request_read(s, client_nfd);
    s->timeout = SEC2USEC(30); // longer timeout for the rest
    if (status != HTTP_STREAM_OK) {
      if (s->status == HTTP_STREAM_CLOSED || s->status == HTTP_STREAM_TIMEOUT) {
        error = 1;
      } else {
        error = 400;
      }
      goto release;
    }
    cs = http_stream_create(HTTP_CLIENT, SEC2USEC(30));
    //http_request_debug_print(s->req);

    fprintf(stderr, "request uri: %s\n", s->req->uri);
    const char *error_at = NULL;
    uri_clear(u);
    if (uri_parse(u, s->req->uri, strlen(s->req->uri), &error_at) == 0) {
      fprintf(stderr, "uri_parse error: %s\n", error_at);
      error = 400;
      goto release;
    }
    uri_normalize(u);
    if (http_stream_connect(cs, u->host, u->port) != HTTP_STREAM_OK) { error = 504; goto release; }
    http_request_header_remove(s->req, "Accept-Encoding");
    http_request_header_remove(s->req, "Proxy-Connection");
    /* TODO: need to expose a copy api for http message */
    http_request_t *tmp_req = cs->req;
    cs->req = s->req;
    char *request_uri = uri_compose_partial(u);
    char *tmp_uri = s->req->uri;
    cs->req->uri = request_uri;
    if (http_stream_request_send(cs) != HTTP_STREAM_OK) { error = 504; goto release; }
    cs->req = tmp_req;
    s->req->uri = tmp_uri;
    free(request_uri);

    /* TODO: fix this. post might not contain data. probably move this logic into stream */
    size_t total = 0;
    if (g_strcmp0("POST", s->req->method) == 0) {
      for (;;) {
        ssize_t nr = sizeof(buf);
        status = http_stream_read(s, buf, &nr);
        fprintf(stderr, "server http_stream_read nr: %zd\n", nr);
        if (nr < 0 || status != HTTP_STREAM_OK) { error = 1; goto release; }
        if (nr == 0) break;
        /*fwrite(buf, sizeof(char), nr, stdout);*/
        ssize_t nw = st_write(cs->nfd, buf, nr, s->timeout);
        if (nw != nr) { error=1; goto release; }
        fprintf(stderr, "st_write nw: %zd\n", nr);
        total += nr;
      }
      fprintf(stderr, "http_stream_read total: %zu\n", total);
    }

    if (http_stream_response_read(cs) != HTTP_STREAM_OK) { error = 502; goto release; }

    /* TODO: properly create a new response and copy headers */
    http_response_t *tmp_resp = s->resp;
    s->resp = cs->resp;
    s->resp->http_version = "HTTP/1.1";
    http_response_header_remove(s->resp, "Content-Length");
    http_response_header_remove(s->resp, "Transfer-Encoding");
    if (s->resp->status_code != 204)
        http_response_header_append(s->resp, "Transfer-Encoding", "chunked");
    ssize_t nw = http_stream_response_send(s, 0);
    s->resp = tmp_resp;

    fprintf(stderr, "http_stream_response_send: %zd\n", nw);
    if (s->resp->status_code != 204 &&
           (cs->content_size > 0 || cs->transfer_encoding == TE_CHUNKED)) {
      total = 0;
      fprintf(stderr, "content size: %zd\n", cs->content_size);
      for (;;) {
        ssize_t nr = sizeof(buf);
        status = http_stream_read(cs, buf, &nr);
        fprintf(stderr, "client http_stream_read nr: %zd\n", nr);
        if (nr <= 0 || status != HTTP_STREAM_OK) break;
        /*fwrite(buf, sizeof(char), nr, stdout);*/
        total += nr;
        if (http_stream_send_chunk(s, buf, nr) != HTTP_STREAM_OK) break;
      }
      fprintf(stderr, "written to client: %zu\n", total);
      if (total > 0 && s->status == HTTP_STREAM_OK) {
        http_stream_send_chunk_end(s);
      } else {
        fprintf(stderr, "for request: %s status: %d\n", s->req->uri, s->status);
      }
    }
release:
    if (!error) {
        if ((g_strcmp0("HTTP/1.1", s->req->http_version) == 0) &&
          (g_strcmp0(http_request_header_getstr(s->req, "Connection"), "close") != 0)) {
          // if HTTP/1.1 client and no Connection: close, then don't close
          should_close = 0;
        } else if (g_strcmp0(http_request_header_getstr(s->req, "Connection"), "keepalive") == 0) {
          should_close = 0;
        }
    }
    http_request_clear(s->req);
    uri_clear(u);
    if (cs) http_stream_close(cs);
    /* TODO: break loop if HTTP/1.0 and not keep-alive */
    if (error) {
      fprintf(stderr, "ERROR: %d STATUS: %d, exiting\n", error, s->status);
      /* TODO: use reason string */
      if (error >= 400 && s->status != HTTP_STREAM_CLOSED) {
        http_response_free(s->resp);
        s->resp = http_response_new(error, "Error");
        http_response_header_append(s->resp, "Content-Length", "0");
        s->status = HTTP_STREAM_OK; /* TODO: might want to move this logic into http_stream */
        http_stream_response_send(s, 0);
      }
      break;
    }
    if (should_close) break;
  }
  fprintf(stderr, "exiting handle_connection (should_close: %u)\n", should_close);
  uri_free(u);
  http_stream_close(s);
  return NULL;
}
Example #11
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;
}
Example #12
0
/* Extract http_pair_t objects from flow's packet_t chain */
int 
flow_extract_http(flow_t *f)
{
	/* check if the flow is carrying HTTP again */
	if( f->http == FALSE)
		return 1;
		
	/*
	 * Find the actual FIN sequences.
	 */
	seq_t	*seq = f->order->src;
	seq_t	*src_fin_seq = NULL;
	seq_t	*dst_fin_seq = NULL;
	int found = 0;
	
	while(seq != NULL)
	{
		/* Update flow's first byte time.
		 * FBT of flow refers to the payload's FBT.
		 */
		if(seq->pkt != NULL && found == 0)
		{
			found = 1;
			f->fb_sec = seq->cap_sec;
			f->fb_usec = seq->cap_usec;
		}
		
		/*Search the FIN sequence in sequence queue.*/
		if(seq->th_flags & TH_FIN == TH_FIN)
		{
			src_fin_seq = seq;
			break;
		}
		seq = seq->next;
	}
	
	seq = f->order->dst;
	while(seq != NULL)
	{
		/*Search the FIN sequence in sequence queue.*/
		if(seq->th_flags & TH_FIN == TH_FIN)
		{
			dst_fin_seq = seq;
			break;
		}
		seq = seq->next;
	}
	
	/*
	 * Set the client and server FIN sequences.
	 */
	seq_t	*fin_seq = NULL;	/* The actual FIN sequence. */
	u_int8_t	fin_dir = 0;	/* fin_dir:
	 * 0: Not set;
	 * 1: src_fin_seq is used;
	 * 2: dst_fin_seq is used;
	 */
	
	if (src_fin_seq != NULL && dst_fin_seq == NULL)
	{
		fin_seq = src_fin_seq;
		fin_dir = 1;
	}
	else if (src_fin_seq == NULL && dst_fin_seq != NULL)
	{
		fin_seq = dst_fin_seq;
		fin_dir = 2;
	}
	else if (src_fin_seq != NULL && dst_fin_seq != NULL)
	{
		fin_seq = src_fin_seq;
		fin_dir = 1;
		if(compare_sequence_time(src_fin_seq, dst_fin_seq) == 1)
		{
			fin_seq = dst_fin_seq;
			fin_dir = 2;
		}
	}
	else
	{
		fin_seq = NULL;
		fin_dir = 0;
	}
	
	/* 
	 * First step: find requests 
	 */
	packet_t *pkt;
	request_t	*req;
	response_t	*rsp;
	int reqn = 0;	// Number of requests.
	int rspn = 0;	// Number of responses.
	
	http_pair_t *new_http = NULL;
	seq_t *seq_next = NULL;	/* for temp */
	seq_t *first_seq = NULL;
	/* Set seq and seq_next */
	seq = f->order->src;
	if( seq != NULL)
	{
		seq_next = seq->next;
	}
	else
	{
		seq_next = NULL;		/* NULL */
	}
	
	if (fin_seq != NULL && seq != NULL)
	{
		/*A FIN packet exists.*/
		while(compare_sequence_time(seq, fin_seq) < 0)
		{
			pkt = seq->pkt;
			if(pkt != NULL && pkt->http == HTTP_REQ)
			{
				/* When a new HTTP request is found,
				 * create a HTTP pair object, then add the object to
				 * flow's HTTP chain.
				 */
				reqn++;
				/* new HTTP pair object*/
				new_http = http_new();
				first_seq = seq;
				new_http->req_fb_sec = seq->cap_sec;
				new_http->req_fb_usec = seq->cap_usec;
				new_http->req_lb_sec = seq->cap_sec;
				new_http->req_lb_usec = seq->cap_usec;
					
				/* Add the object to flow's HTTP chain */
				flow_add_http(f, new_http);
				/* new request object */
				req = http_request_new();
				/* Add the request object to the foregoing HTTP pair object */
				http_add_request(new_http, req);
				/* parse and write values to foregoing request object */
				http_parse_request(req, pkt->tcp_odata, pkt->tcp_odata + pkt->tcp_dl);
			}
			else
			{
				/*Omit the TCP handshake sequences.*/
				if(new_http == NULL)
				{
					seq = seq->next;
					if(seq != NULL)
						seq_next = seq->next;
					else
						break;
					continue;
				}
			}

			if( new_http != NULL )
			{
				if( seq_next == NULL || seq_next == fin_seq || seq_next->pkt != NULL ||\
						compare_sequence_time(seq_next, fin_seq) >= 0 ){
					//assert(seq->nxt_seq != 0);
					if( seq->nxt_seq != 0){
						new_http->req_total_len = seq->nxt_seq - first_seq->seq;
						new_http->req_body_len = 0;
					}
					/*Update flow's last byte time.*/
					if ((seq->cap_sec > f->lb_sec) || (seq->cap_sec == f->lb_sec && seq->cap_usec > f->lb_usec))
					{
						f->lb_sec = seq->cap_sec;
						f->lb_usec = seq->cap_usec;
					}
				}
				else
				{
					//assert(seq->seq <= seq_next->seq);
				}
			}
			
			/* Continue to next sequence.*/
			seq = seq->next;
			if(seq != NULL)
				seq_next = seq->next;
			else
				break;
		}
	}
	else
	{
		/* No FIN packet found.*/
		while(seq != NULL)
		{
			pkt = seq->pkt;
			if(pkt != NULL && pkt->http == HTTP_REQ)
			{
				/* When a new HTTP request is found,
				 * create a HTTP pair object, then add the object to
				 * flow's HTTP chain.
				 */
				reqn++;
				/* new HTTP pair object*/
				new_http = http_new();
				first_seq = seq;
				new_http->req_fb_sec = seq->cap_sec;
				new_http->req_fb_usec = seq->cap_usec;
				new_http->req_lb_sec = seq->cap_sec;
				new_http->req_lb_usec = seq->cap_usec;
				
				/* Add the object to flow's HTTP chain */
				flow_add_http(f, new_http);
				/* new request object */
				req = http_request_new();
				/* Add the request object to the foregoing HTTP pair object */
				http_add_request(new_http, req);
				/* parse and write values to foregoing request object */
				http_parse_request(req, pkt->tcp_odata, pkt->tcp_odata + pkt->tcp_dl);
			}
			else
			{
				if(new_http == NULL)
				{
					/*Omit the TCP handshake sequences.*/
					seq = seq->next;
					if(seq != NULL)
						seq_next = seq->next;
					else
						break;
					continue;
				}
			}
			if( new_http != NULL )
			{
				if( seq_next == NULL || seq_next->pkt != NULL )
				{
					//assert(seq->nxt_seq != 0);
					if( seq->nxt_seq != 0){
						new_http->req_total_len = seq->nxt_seq - first_seq->seq;
						new_http->req_body_len = 0;
					}
					/*Update flow's last byte time.*/
					if ((seq->cap_sec > f->lb_sec) || (seq->cap_sec == f->lb_sec && seq->cap_usec > f->lb_usec))
					{
						f->lb_sec = seq->cap_sec;
						f->lb_usec = seq->cap_usec;
					}
				}
				else
				{
					//assert(seq->seq <= seq_next->seq);
				}
			}
			/*Continue to next sequence.*/
			seq = seq->next;
			if(seq != NULL)
				seq_next = seq->next;
			else
				break;
		}
	}

	/* If no responses found, we treat the flow as invalid and stop parsing */
	if(reqn == 0)
		return 1;
		
	/* Second step: find responses */
	http_pair_t *tmp = f->http_f;
	http_pair_t *found_http = NULL;
	seq = f->order->dst;
	if( seq != NULL)
		seq_next = seq->next;
	else
		seq_next = NULL;		/* NULL */
	if(fin_seq != NULL && seq != NULL){
		/*There is FIN packet.*/
		while(compare_sequence_time(seq, fin_seq) < 0)
		{
			pkt = seq->pkt;
			if ( pkt != NULL && pkt->http == HTTP_RSP)
			{
				/*
				 * Similar to the request parsing, a new response is
				 * added to the first pair without response
				 */
				rspn++;
				/* Try to find the first pair without response */
				while(tmp != NULL)
				{
					if(tmp->response_header == NULL)
						break;
					tmp = tmp->next;
				}
				if(tmp == NULL)
					/* no response empty, then return */
					return 1;
				else
				{
					/*Found!*/
					found_http = tmp;
					first_seq = seq;
					found_http->rsp_fb_sec = seq->cap_sec;
					found_http->rsp_fb_usec = seq->cap_usec;
					rsp = http_response_new();
					http_add_response(found_http, rsp);
					http_parse_response(rsp, pkt->tcp_odata, pkt->tcp_odata + pkt->tcp_dl);
				}
			}
			else
			{
				if(found_http == NULL)
				{
					seq = seq->next;
					if(seq != NULL)
						seq_next = seq->next;
					else
						break;
					continue;
				}
			}

			if ( found_http != NULL )
			{
				/*first_seq != NULL*/
				if( seq_next == NULL || seq_next == fin_seq || seq_next->pkt != NULL ||\
						compare_sequence_time(seq_next, fin_seq) >= 0 )
				{
					found_http->rsp_lb_sec = seq->cap_sec;
					found_http->rsp_lb_usec = seq->cap_usec;
					//assert( seq->nxt_seq != 0 );
					if(seq->nxt_seq != 0){
						found_http->rsp_total_len = seq->nxt_seq - first_seq->seq;
						//printf("%d,%d", found_http->rsp_total_len, found_http->response_header->hdlen);
						//assert(found_http->rsp_total_len >= found_http->response_header->hdlen);
						found_http->rsp_body_len = found_http->rsp_total_len - found_http->response_header->hdlen;
					}
					/*Update flow's last byte time.*/
					if ((seq->cap_sec > f->lb_sec) || (seq->cap_sec == f->lb_sec && seq->cap_usec > f->lb_usec))
					{
						f->lb_sec = seq->cap_sec;
						f->lb_usec = seq->cap_usec;
					}
				}
				else
				{
					//assert(seq->seq <= seq_next->seq);
				}
			}

			seq = seq->next;
			if(seq != NULL)
				seq_next = seq->next;
			else
				break;
		}
	}
	else
	{
		/*There is no FIN packet.*/
		while(seq != NULL)
		{
			pkt = seq->pkt;
			if ( pkt != NULL && pkt->http == HTTP_RSP )
			{
				/*
				 * Similar to the request parsing, a new response is
				 * added to the first pair without response
				 */
				rspn++;
				/* Try to find the first pair without response */
				while(tmp != NULL)
				{
					if(tmp->response_header == NULL)
						break;
					tmp = tmp->next;
				}
				if(tmp == NULL)
					/* no response empty, then return */
					return 1;
				else
				{
					/*Found!*/
					found_http = tmp;
					first_seq = seq;
					found_http->rsp_fb_sec = seq->cap_sec;
					found_http->rsp_fb_usec = seq->cap_usec;
					rsp = http_response_new();
					http_add_response(found_http, rsp);
					http_parse_response(rsp, pkt->tcp_odata, pkt->tcp_odata + pkt->tcp_dl);
				}
			}
			else
			{
				if(found_http == NULL)
				{
					seq = seq->next;
					if(seq != NULL)
						seq_next = seq->next;
					else
						break;
					continue;
				}
			}

			if ( found_http != NULL )
			{
				/*first_seq != NULL*/
				if( seq_next == NULL || seq_next->pkt != NULL )
				{
					found_http->rsp_lb_sec = seq->cap_sec;
					found_http->rsp_lb_usec = seq->cap_usec;
					//assert( seq->nxt_seq != 0 );
					if(seq->nxt_seq != 0){
						found_http->rsp_total_len = seq->nxt_seq - first_seq->seq;	
						assert(found_http->rsp_total_len >= found_http->response_header->hdlen);
						found_http->rsp_body_len = found_http->rsp_total_len - found_http->response_header->hdlen;
					}
					/*Update flow's last byte time.*/
					if ((seq->cap_sec > f->lb_sec) || (seq->cap_sec == f->lb_sec && seq->cap_usec > f->lb_usec))
					{
						f->lb_sec = seq->cap_sec;
						f->lb_usec = seq->cap_usec;
					}
				}
				else
				{
					//assert(seq->seq <= seq_next->seq);
				}
			}

			seq = seq->next;
			if(seq != NULL)
				seq_next = seq->next;
			else
				break;
		}
	}
	return 0;
}
Example #13
0
void
wiki_handle_http_request(HttpRequest *req)
{
    HttpResponse *res      = http_response_new(req);
    char         *page     = http_request_get_path_info(req);
    char         *command  = http_request_get_query_string(req);
    char         *wikitext = "";

    util_dehttpize(page); 	/* remove any encoding on the requested
				   page name.                           */

    if (!strcmp(page, "/"))
    {
        if (access("WikiHome", R_OK) != 0)
            wiki_redirect(res, "/WikiHome?create");
        page = "/WikiHome";
    }

    if (!strcmp(page, "/styles.css"))
    {
        /*  Return CSS page */
        http_response_set_content_type(res, "text/css");
        http_response_printf(res, "%s", CssData);
        http_response_send(res);
        exit(0);
    }

    if (!strcmp(page, "/favicon.ico"))
    {
        /*  Return favicon */
        http_response_set_content_type(res, "image/ico");
        http_response_set_data(res, FaviconData, FaviconDataLen);
        http_response_send(res);
        exit(0);
    }


    page = page + 1; 		/* skip slash */

    if (!strncmp(page, "api/", 4))
    {
        char *p;

        page += 4;
        for (p=page; *p != '\0'; p++)
            if (*p=='?') {
                *p ='\0';
                break;
            }

        wiki_handle_rest_call(req, res, page);
        exit(0);
    }

    /* A little safety. issue a malformed request for any paths,
     * There shouldn't need to be any..
     */
    if (strchr(page, '/'))
    {
        http_response_set_status(res, 404, "Not Found");
        http_response_printf(res, "<html><body>404 Not Found</body></html>\n");
        http_response_send(res);
        exit(0);
    }

    if (!strcmp(page, "Changes"))
    {
        wiki_show_changes_page(res);
    }
    else if (!strcmp(page, "ChangesRss"))
    {
        wiki_show_changes_page_rss(res);
    }
    else if (!strcmp(page, "Search"))
    {
        wiki_show_search_results_page(res, http_request_param_get(req, "expr"));
    }
    else if (!strcmp(page, "Create"))
    {
        if ( (wikitext = http_request_param_get(req, "title")) != NULL)
        {
            /* create page and redirect */
            wiki_redirect(res, http_request_param_get(req, "title"));
        }
        else
        {
            /* show create page form  */
            wiki_show_create_page(res);
        }
    }
    else
    {
        /* TODO: dont blindly write wikitext data to disk */
        if ( (wikitext = http_request_param_get(req, "wikitext")) != NULL)
        {
            file_write(page, wikitext);
        }

        if (access(page, R_OK) == 0) 	/* page exists */
        {
            wikitext = file_read(page);

            if (!strcmp(command, "edit"))
            {
                /* print edit page */
                wiki_show_edit_page(res, wikitext, page);
            }
            else
            {
                wiki_show_page(res, wikitext, page);
            }
        }
        else
        {
            if (!strcmp(command, "create"))
            {
                wiki_show_edit_page(res, NULL, page);
            }
            else
            {
                char buf[1024];
                snprintf(buf, 1024, "%s?create", page);
                wiki_redirect(res, buf);
            }
        }
    }

}