Make content-length not buggy as hell

This commit is contained in:
Nick Krichevsky 2018-09-02 01:26:01 -04:00
parent 30fe078447
commit 5bbda3dd24
3 changed files with 48 additions and 34 deletions

View file

@ -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;
}

View file

@ -1,6 +1,7 @@
#include "http_types.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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);

View file

@ -2,6 +2,7 @@
#include "socket_helper.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -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
}