/* * 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); }
/* ** 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); }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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); } } } }