From 09c95f472bbbc3636ff6bbc9cff42fab8dc11287 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Sat, 4 Apr 2020 12:08:45 +0200 Subject: [PATCH] wip --- a.out | Bin 0 -> 164324 bytes server.cc | 268 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 196 insertions(+), 72 deletions(-) create mode 100755 a.out diff --git a/a.out b/a.out new file mode 100755 index 0000000000000000000000000000000000000000..21a2ce90d6bca6786735e1397e26e5411c4e74b1 GIT binary patch literal 164324 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 headers) { while(true) { // probe first two chars to see if body will start @@ -144,18 +192,24 @@ bool parse_headers(FILE* in, map& headers) { fgetc(in); // \n headers[header_name] = value; - cout << header_name << ": " << value << endl; } return true; } -bool has_body(char* method) { +/** + * Returns true if it is customary for the given HTTP method to have a body + */ +bool has_body(const char* method) { return !strcmp(method, "POST") || !strcmp(method, "PUT"); } -bool is_chunk_start(char* buf) { - char* i; +/** + * Returns true if the given string contains a valid HTTP 1.1 chunk start + * delimiter, false otherwise. + */ +bool is_chunk_start(const char* buf) { + const char* i; for (i = buf; isdigit(*i); i++); if (*i != '\r') return false; i++; @@ -164,65 +218,84 @@ bool is_chunk_start(char* buf) { return *i == '\0'; } +/** + * Returns true if the given buffer contains a valid HTTP 1.1 chunk end + * delimiter at its very end, false otherwise. + */ +bool is_chunk_end(vector& body) { + const char b = body.back(); + body.pop_back(); + + const char a = body.back(); + body.push_back(b); + + return a == '\r' && b == '\n'; +} + +/** + * Fetch and parse HTTP body from given file, assuming the header has already + * been parsed. Parses bodies either delimited by Content-Length or endoded + * using HTTP 1.1 chunds. If the body appears to not meet this criteria (by + * inspecting the HTTP headers), false is returned, otherwise returns true. + */ bool fetch_body(FILE* in, vector& body, const map headers) { bool chunked; - size_t length, r = 0; + size_t length; - auto p = headers.find("Content-Length"); - chunked = p == headers.end(); + { + auto p = headers.find("Content-Length"); + chunked = p == headers.end(); - if (!chunked) { - length = atol(p->second.c_str()); - } else { - auto q = headers.find("Transfer-Encoding"); - if (q == headers.end() || q->second != "chunked") { - return false; + if (!chunked) { + length = atol(p->second.c_str()); + } else { + auto q = headers.find("Transfer-Encoding"); + if (q == headers.end() || q->second != "chunked") { + return false; + } } } if (!chunked) { // read Content-Length bytes - uint8_t buf[8192]; - const size_t n = atol(p->second.c_str()); - for(size_t w = 0; w < n;) { - ssize_t r = fread(buf, 1, (n - w) > 8192 ? 8192 : (n - w), in); + uint8_t buf[BUFFER]; + size_t r; + + for(size_t w = 0; w < length; w += r) { + r = fread(buf, 1, (length - w) > BUFFER ? BUFFER : (length - w), in); if (r == -1) return false; body.insert(end(body), begin(buf), end(buf)); - w += r; } } else { // This was implemented before Prof. Carzaniga said chunked encoding is not // required. I am leaving this just because it is already done. // Read chunks and search for final chunk 0\r\n\r\n - char buf[8193]; - bool chunk_start = true; + char buf[BUFFER + 1]; + buf[BUFFER] = '\0'; + bool will_chunk_start = true; while (true) { - fgets(buf, 8193, in); + size_t len; + for (len = 0; len < BUFFER; len++) { + if ((buf[len] = fgetc(in)) == '\n') { + buf[len + 1] = '\0'; + break; + } + } - if (!strcmp(buf, "0\r\n") && chunk_start) { + if (!strcmp(buf, "0\r\n") && will_chunk_start) { break; } - if (chunk_start && is_chunk_start(buf)) { + if (will_chunk_start && is_chunk_start(buf)) { continue; } body.insert(end(body), begin(buf), end(buf)); body.pop_back(); - char b = body.back(); - body.pop_back(); - char a = body.back(); - body.pop_back(); - if (a != '\r' || b != '\n') { - body.push_back(a); - body.push_back(b); - } - - size_t len = strlen(buf); - chunk_start = len > 2 && buf[len-2] == '\r' && buf[len-1] == '\n'; + will_chunk_start = is_chunk_end(body); } body.insert(end(body), begin(buf), end(buf)); @@ -233,6 +306,10 @@ bool fetch_body(FILE* in, vector& body, return true; } +/** + * Sends an HTTP response with status code and message given. Then proceeds to + * close the given input and output files and terminates the current thread. + */ void send_error(FILE* in, FILE* out, const char* protocol, const int status, const string message) { const char* msg = message.c_str(); @@ -265,6 +342,11 @@ void send_error(FILE* in, FILE* out, const char* protocol, const int status, pthread_exit(NULL); } +/** + * Parses the HTTP method name given as string and sets cURL options + * accordingly. Returns false if method is not supported on unknown, true + * otherwise + */ bool set_curl_method(CURL* c, const char* method) { if (!strcmp(method, "GET")) { curl_easy_setopt(c, CURLOPT_HTTPGET, 1); @@ -278,7 +360,6 @@ bool set_curl_method(CURL* c, const char* method) { } else if (!strcmp(method, "DELETE")) { curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); } else { - //TODO: implement CONNECT method return false; } @@ -319,13 +400,13 @@ size_t write_buffer(void *ptr, size_t size, size_t nmemb, memcpy((rbody->data + index), ptr, n); rbody->data[rbody->size] = '\0'; - cout << "copy " << n << " size " << rbody->size << endl; - return size * nmemb; } -// Converts url in a zero-terminated string for the host name. Port is retured -// as integer, -1 on error +/** + * Converts url in a zero-terminated string for the host name. Port is retured + * as integer, -1 on error + */ int find_host_port(char* url) { char* i = url; size_t c = 0; @@ -388,10 +469,12 @@ void* forwarder_thread(void* data) { return NULL; } -void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, - const int fd) { +/** + * Returns a socket file descriptof of a newly opened socket to the given host. + */ +int open_client_socket(FILE* in, FILE* out, const char* protocol, char* host) { int port; - if ((port = find_host_port(url)) == -1) { + if ((port = find_host_port(host)) == -1) { send_error(in, out, protocol, 500, "Hostname parse error"); } @@ -400,7 +483,7 @@ void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, send_error(in, out, protocol, 500, "TCP socket connection error"); } - struct hostent *he = gethostbyname(url); + struct hostent *he = gethostbyname(host); if (!he) { send_error(in, out, protocol, 404, "Unknown host"); } @@ -409,7 +492,7 @@ void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, memset (&locale, 0, sizeof(struct sockaddr_in)); locale.sin_family = AF_INET; - locale.sin_addr.s_addr = htonl(INADDR_ANY); + locale.sin_addr.s_addr = htonl(INADDR_ANY); locale.sin_port = htons(0); if (::bind(socketfd, (struct sockaddr*) &locale, sizeof(locale)) == -1) { @@ -427,10 +510,23 @@ void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, send_error(in, out, protocol, 500, "TCP socket connection error"); } + return socketfd; +} + +/** + * Handle HTTP connect method. Opens a client socket to the host in *url (by + * doing a dns query first). Then forks in another threads and starts relaying + * data both from the HTTP client socket to the newly opened socket and + * videversa. + */ +void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, + const int fd) { + + int socketfd = open_client_socket(in, out, protocol, url); + struct forward from = { .in = fd, .out = socketfd }, to = { .in = socketfd, .out = fd }; - fprintf(out, "%s %d %s\r\n\r\n", protocol, 200, "Connection established"); fflush(out); @@ -481,7 +577,9 @@ void* request_thread(void* data) { map headers; vector body; - if (fscanf(in, "%10s %8000s %10s\r\n", method, url, protocol) < 3) { + int i; + if ((i = fscanf(in, "%10s %8000s %10s\r\n", method, url, protocol)) < 3) { + if (i < 0) break; send_error(in, out, protocol, 400, "Bad request line"); } @@ -516,7 +614,30 @@ void* request_thread(void* data) { handle_connect(in, out, protocol, url, fd); break; } else { - struct buffer rhead; + + // Delete Proxy-Connection header + { + auto i = headers.find("Proxy-Connection"); + if (i != headers.end()) headers.erase(i); + } + + if (strncmp(url, "http://", 7) { + send_error(in. out, protocol, 400, "Protocol in URL not supported"); + } + + char* host = url + 7; + + int serverfd = open_client_socket(in, out, protocol, host); + FILE* in = fdopen(dup(serverfd), "r"); + FILE* out = fdopen(dup(serverfd), "w"); + + fprintf("%s %s %s\r\n", method, url, protocol); + for (auto i = headers.begin(); i != headers.end(); i++) { + fprintf("%s: %s\r\n", i->first.c_str(), i->second.c_str()); + } + + + /*struct buffer rhead; struct buffer rbody; buffer_init(&rhead); buffer_init(&rbody); @@ -538,14 +659,6 @@ void* request_thread(void* data) { curl_easy_setopt(curl, CURLOPT_URL, url); - // Delete Proxy-Connection header - { - auto i = headers.find("Proxy-Connection"); - if (i != headers.end()) { - headers.erase(i); - } - } - struct curl_slist *chunk = NULL; for (auto i = headers.begin(); i != headers.end(); i++) { string header = i->first + ": " + i->second; @@ -571,7 +684,7 @@ void* request_thread(void* data) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); send_error(in, out, protocol, 502, "Request to server failed"); - } else { + } else*/ { char protocol_r[10]; char message[8000]; unsigned code; @@ -606,35 +719,44 @@ void* request_thread(void* data) { Magick::Blob my_blob(rbody.data, rbody.size); Magick::Blob output; - Magick::Image to_rotate(my_blob); - to_rotate.magick(image); - to_rotate.flip(); - to_rotate.write(&output); + Magick::Image to_rotate; - cout << "IN" << endl << my_blob.length() << endl; - cout << "OUT" << endl << output.length() << endl; + try { + to_rotate = Magick::Image(my_blob); + } catch(Magick::Warning& ignored) {} + + try { + to_rotate.magick(image); + } catch(Magick::Warning& ignored) {} + + try { + switch (alteration) { + case FLIP: to_rotate.flip(); break; + case LEFT: to_rotate.rotate(-90); break; + case RIGHT: to_rotate.rotate(90); break; + } + } catch(Magick::Warning& ignored) {} + + try { + to_rotate.write(&output); + } catch(Magick::Warning& ignored) {} fprintf(out, "%s %u %s\n", protocol_r, code, message); - cout << protocol_r << ' ' << code << ' ' << message << endl; headers["Content-Length"] = to_string(output.length()); + headers["Connection"] = "keep-alive"; for (auto i = headers.begin(); i != headers.end(); i++) { string header = i->first + ": " + i->second + "\r\n"; - fprintf(out, "%s\n", header.c_str()); - cout << header << endl; + fprintf(out, "%s", header.c_str()); } fprintf(out, "\r\n"); fflush(out); total_write((uint8_t*) output.data(), output.length(), fd); } catch (Magick::Exception &error) { + cout << "Magick++ image conversion failed: " << error.what() + << endl; send_error(in, out, protocol, 500, "Image conversion failed"); - fprintf(stderr, "I exit %s\n", error.what()); - break; - } catch (std::exception &error) { - send_error(in, out, protocol, 500, "Image conversion failed"); - fprintf(stderr, "I exit %s\n", error.what()); - break; } } else { total_write(rhead.data, rhead.size, fd); @@ -666,3 +788,5 @@ void* request_thread(void* data) { pthread_exit(NULL); } + +