diff --git a/client/http_socket.c b/client/http_socket.c index 3100ee7..b28fec3 100644 --- a/client/http_socket.c +++ b/client/http_socket.c @@ -47,7 +47,7 @@ struct http_message build_basic_request(const char *method, const char *host, co int path_length = strlen(path) + 1; message.path = malloc(path_length * sizeof(char)); - strcpy(message.path, host); + strcpy(message.path, path); const char *request_line_components[] = {method, " ", path, " ", HTTP_VERSION, "\r\n"}; const char *host_header[] = {"Host: ", host, "\r\n"}; @@ -122,8 +122,12 @@ char *send_request(struct http_message req) { } send(socket_fd, req.contents, strlen(req.contents), 0); - char * remote_parts = get_all_remote_parts(socket_fd); + struct http_message res; + memset(&res, 0, sizeof(struct http_message)); + enum socket_read_result result = get_all_remote_parts(socket_fd, &res); + printf("result: %d\n", result); + printf("%s", res.contents); close(socket_fd); - return remote_parts; + return res.contents; } diff --git a/common/http_types.c b/common/http_types.c index a2bb93d..a7d110c 100644 --- a/common/http_types.c +++ b/common/http_types.c @@ -1,6 +1,7 @@ #include "http_types.h" #include #include +#include #include #include @@ -14,13 +15,14 @@ static char *strcpy_lstrip(char *dest, const char *src) { char *dest_cursor; const char *src_cursor; bool non_whitespace_hit = false; - for (dest_cursor = dest, src_cursor = src; *src_cursor != '\0'; (dest_cursor++, src_cursor++)) { + for (dest_cursor = dest, src_cursor = src; *src_cursor != '\0'; src_cursor++) { if (non_whitespace_hit || !(*src_cursor == ' ' || *src_cursor == '\t')) { - *dest_cursor = *src_cursor; - } else { non_whitespace_hit = true; + *dest_cursor = *src_cursor; + dest_cursor++; } } + *dest_cursor = '\0'; return dest; } @@ -43,7 +45,7 @@ struct http_header *insert_header(const char *header_name, const char *header_va new_header->name = malloc(name_length * sizeof(char)); strcpy(new_header->name, header_name); - int contents_length = strlen(header_name) + 1; + int contents_length = strlen(header_value) + 1; new_header->value = malloc(contents_length * sizeof(char)); strcpy_lstrip(new_header->value, header_value); diff --git a/common/socket_helper.c b/common/socket_helper.c index 763ae8d..7ff3cc7 100644 --- a/common/socket_helper.c +++ b/common/socket_helper.c @@ -2,6 +2,7 @@ #include "socket_helper.h" #include #include +#include #include #include @@ -47,24 +48,26 @@ static struct line_read_result read_line(const char *buffer, int buffer_size, st int line_length = 0; const char *header_delim = NULL; - const char *prev_cursor = NULL; for (const char *cursor = buffer; cursor != line_terminator; (cursor++, line_length++)) { - if (*cursor == ':') { + if (header_delim == NULL && *cursor == ':') { header_delim = cursor; } - prev_cursor = cursor; } + struct line_read_result result; - // If the last character was a \r, we must have a CRLF sequence. - if (prev_cursor != NULL && *prev_cursor == '\r') { - result.line_type = RESULT_BLANK_LINE; - } else if (header_delim != NULL) { - result.line_type = RESULT_HEADER_LINE; + // Add the space for the \n + int line_size = line_length + 1; + result.line = malloc((line_size + 1) * sizeof(char)); + memcpy(result.line, buffer, line_size); + result.line[line_size] = '\0'; + result.bytes_read = line_size; + if (header_delim != NULL) { + result.line_type = RESULT_HEADER; int name_size = header_delim - buffer; char *header_name = malloc((name_size + 1) * sizeof(char)); - // Start of the buffer + the number of bytes read - 1 for the \r + // Need to subtract \r\n and colon. // TODO: Support line-continued headers - int value_size = (line_terminator - buffer) + line_length - 1; + int value_size = line_size - name_size - 3; char *header_value = malloc((value_size + 1) * sizeof(char)); memcpy(header_name, buffer, name_size); header_name[name_size] = '\0'; @@ -77,16 +80,10 @@ static struct line_read_result read_line(const char *buffer, int buffer_size, st } free(header_value); free(header_name); + } else if (strcmp(result.line, "\r\n") == 0) { + result.line_type = RESULT_BLANK_LINE; } else { result.line_type = RESULT_START_LINE; - } - // Add the space for the \n - int line_size = line_length + 1; - result.line = malloc((line_size + 1) * sizeof(char)); - memcpy(result.line, buffer, line_size); - result.line[line_size] = '\0'; - result.bytes_read = line_size; - if (result.line_type == RESULT_START_LINE) { message->start_line = malloc((line_size + 1) * sizeof(char)); strcpy(message->start_line, result.line); message->start_line = result.line; @@ -106,7 +103,6 @@ static struct socket_read_info get_read_info(const struct http_header *headers) const struct http_header *header_cursor = headers; struct socket_read_info info = {STRATEGY_EOF, -1}; while (header_cursor != NULL) { - header_cursor = header_cursor->next_header; if (headercmp(header_cursor, HEADER_TRANSFER_ENCODING) == 0 && case_insensitive_strcmp(header_cursor->value, ENCODING_TYPE_CHUNKED)) { info.strategy = STRATEGY_CHUNKED; @@ -115,6 +111,7 @@ static struct socket_read_info get_read_info(const struct http_header *headers) info.strategy = STRATEGY_CONTENT_LENGTH; info.length = atoi(header_cursor->value); } + header_cursor = header_cursor->next_header; } return info; @@ -126,9 +123,13 @@ static char *read_body_by_content_length(int socket_fd, int content_length) { int total_bytes_read = 0; int bytes_read = 0; int write_offset = 0; - while ((total_bytes_read += bytes_read = read(socket_fd, buffer, content_length)) < content_length && bytes_read > 0) { - memcpy(result + write_offset, buffer, content_length) + while ((total_bytes_read += bytes_read = read(socket_fd, buffer, content_length)) <= content_length && bytes_read > 0) { + memcpy(result + write_offset, buffer, content_length); write_offset += bytes_read; + // If we've read exactly the number of bytes we need to, we don't need to wait for more data. + if (total_bytes_read == content_length) { + break; + } } free(buffer); result[total_bytes_read] = '\0'; @@ -144,21 +145,21 @@ enum socket_read_result get_all_remote_parts(int socket_fd, struct http_message ssize_t bytes_read; int write_offset = 0; bool have_start_line = false; + bool have_blank_line = false; // Loop through all available info until we hit the end of the headers. - while ((bytes_read = read(socket_fd, buffer, BUFFER_SIZE)) > 0) { + while (!have_blank_line && (bytes_read = read(socket_fd, buffer, BUFFER_SIZE)) > 0) { + current_result_size += bytes_read; //Allocate a new result buffer if we need to, otherwise grow the existing one. if (result == NULL) { result = malloc(bytes_read); read_cursor = result; } else { - write_offset = current_result_size; - current_result_size += bytes_read; result = realloc(result, current_result_size); } - memcpy(result + write_offset, buffer, BUFFER_SIZE); + memcpy(result + write_offset, buffer, bytes_read); struct line_read_result line_result; memset(&line_result, 0, sizeof(struct line_read_result)); - while ((line_result = read_line(read_cursor, result + current_result_size - read_cursor, message), + while ((line_result = read_line(read_cursor, current_result_size, message), line_result.line_type != RESULT_NO_LINE)) { read_cursor += line_result.bytes_read; free(line_result.line); @@ -172,6 +173,7 @@ enum socket_read_result get_all_remote_parts(int socket_fd, struct http_message return RESULT_MALFORMED; } else if (line_result.line_type == RESULT_BLANK_LINE) { // If we hit a blank line, we're done reading headers. + have_blank_line = true; break; } else if (line_result.line_type == RESULT_START_LINE) { if (have_start_line) { @@ -184,13 +186,19 @@ enum socket_read_result get_all_remote_parts(int socket_fd, struct http_message have_start_line = true; } } + write_offset += current_result_size; } struct socket_read_info read_info = get_read_info(message->headers); char *body_result; if (read_info.strategy == STRATEGY_CHUNKED) { // TODO: Implement } else if (read_info.strategy == STRATEGY_CONTENT_LENGTH) { - body_result = read_body_by_content_length(socket_fd, read_info.length); + int header_length = read_cursor - result; + int net_content_length = read_info.length - (current_result_size - header_length); + // Include space for null term + current_result_size += net_content_length + 1; + result = realloc(result, current_result_size); + body_result = read_body_by_content_length(socket_fd, net_content_length); } else { // TODO: Implement }