diff options
| -rw-r--r-- | main.c | 150 |
1 files changed, 103 insertions, 47 deletions
| @@ -1,51 +1,25 @@ | |||
| 1 | #include <netinet/in.h> | 1 | #include <netinet/in.h> |
| 2 | #include <stdio.h> | 2 | #include <stdio.h> |
| 3 | #include <stdio_ext.h> | ||
| 3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 4 | #include <string.h> | 5 | #include <string.h> |
| 5 | #include <sys/socket.h> | 6 | #include <sys/socket.h> |
| 6 | #include <sys/epoll.h> | 7 | #include <sys/epoll.h> |
| 8 | #include <sys/sendfile.h> | ||
| 7 | #include <fcntl.h> | 9 | #include <fcntl.h> |
| 8 | #include <unistd.h> | 10 | #include <unistd.h> |
| 11 | #include <poll.h> | ||
| 9 | 12 | ||
| 10 | #include <err.h> | 13 | #include <err.h> |
| 11 | #include <errno.h> | 14 | #include <errno.h> |
| 12 | 15 | ||
| 13 | #include <pthread.h> | 16 | #include <pthread.h> |
| 14 | 17 | ||
| 15 | void * next_customer(void * new_socket) | ||
| 16 | { | ||
| 17 | if (new_socket == 0) return NULL; | ||
| 18 | |||
| 19 | |||
| 20 | // read the input data... | ||
| 21 | char * input_buffer = {0}; | ||
| 22 | size_t input_buffer_position = 0; | ||
| 23 | FILE * f_input = open_memstream(&input_buffer, &input_buffer_position); | ||
| 24 | |||
| 25 | |||
| 26 | for( | ||
| 27 | int size=1024, | ||
| 28 | read_buffer[1024] = {0}; | ||
| 29 | size>0; | ||
| 30 | size=recv((size_t) new_socket, read_buffer, 1024, MSG_WAITALL)) { | ||
| 31 | fwrite(read_buffer, size, 1, f_input); | ||
| 32 | usleep(10); // TODO: implement with some sort of epoll | ||
| 33 | } | ||
| 34 | |||
| 35 | fflush(f_input); | ||
| 36 | printf("input_buffer has %ld bytes and contains:\n", input_buffer_position); | ||
| 37 | |||
| 38 | char * c = strstr(input_buffer, "Content-Type"); | ||
| 39 | printf("WE ARE HERE: %s\n", c); | ||
| 40 | write(STDOUT_FILENO, input_buffer, input_buffer_position); | ||
| 41 | |||
| 42 | |||
| 43 | 18 | ||
| 44 | // answer the call... | ||
| 45 | 19 | ||
| 46 | char * buffer = {0}; | 20 | void send_answer(void * new_socket) { |
| 47 | size_t buffer_position = 0; | 21 | FILE * f = fdopen((size_t) new_socket, "w"); |
| 48 | FILE * f = open_memstream(&buffer, &buffer_position); | 22 | puts("> sending answer..."); |
| 49 | fputs("HTTP/1.0 200 OK\n", f); | 23 | fputs("HTTP/1.0 200 OK\n", f); |
| 50 | fputs("content-type: text/html\n\n", f); | 24 | fputs("content-type: text/html\n\n", f); |
| 51 | fputs("<html>", f); | 25 | fputs("<html>", f); |
| @@ -57,19 +31,101 @@ void * next_customer(void * new_socket) | |||
| 57 | fputs("<label>Line1<br/>\n", f); | 31 | fputs("<label>Line1<br/>\n", f); |
| 58 | fputs("<textarea type=\"text\" name=\"text\"></textarea>", f); | 32 | fputs("<textarea type=\"text\" name=\"text\"></textarea>", f); |
| 59 | fputs("</label><br/>\n", f); | 33 | fputs("</label><br/>\n", f); |
| 34 | fputs("<input type=\"file\" name=\"okay\" value=\"ok\" />", f); | ||
| 60 | fputs("<input type=\"submit\" name=\"okay\" value=\"ok\" />", f); | 35 | fputs("<input type=\"submit\" name=\"okay\" value=\"ok\" />", f); |
| 61 | fputs("</form>", f); | 36 | fputs("</form>", f); |
| 62 | fputs("</html>\n", f); | 37 | fputs("</html>\n\0", f); |
| 63 | fflush(f); | 38 | fflush(f); |
| 64 | printf("OOOOO [%ld] %s\n", buffer_position, buffer); | 39 | puts("> answer sent."); |
| 65 | |||
| 66 | send((size_t) new_socket, buffer, buffer_position, MSG_EOR); | ||
| 67 | // fclose(f_socket); | ||
| 68 | close((size_t) new_socket); | ||
| 69 | fclose(f_input); | ||
| 70 | fclose(f); | 40 | fclose(f); |
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | // #define FOREACH_HEADER(HEADER) \ | ||
| 45 | // HEADER("Content-Type: multipart/form-data; boundary=") | ||
| 46 | // #define GENERATE_HEADERS(H) sizeof(H), H | ||
| 47 | // | ||
| 48 | // typedef struct { | ||
| 49 | // const int length; | ||
| 50 | // const char * string; | ||
| 51 | // } length_value; | ||
| 52 | // | ||
| 53 | // const length_value headers[] = { | ||
| 54 | // FOREACH_HEADER(GENERATE_HEADERS) | ||
| 55 | // }; | ||
| 56 | |||
| 57 | |||
| 58 | void * next_customer(void * new_socket) { | ||
| 59 | if (new_socket == 0) return NULL; | ||
| 60 | |||
| 61 | const int MAX_HEADER_LINE_LENGTH = 1024; | ||
| 62 | const int MAX_BOUNDARY_LENGTH = 64; | ||
| 63 | |||
| 64 | char boundary[64] = {0}; | ||
| 65 | int boundary_size = 0; | ||
| 66 | |||
| 67 | usleep(100); // wait to avoid poll, epoll or evil select | ||
| 68 | |||
| 69 | FILE * f = fdopen((size_t) new_socket, "r"); | ||
| 70 | char buffer[MAX_HEADER_LINE_LENGTH]; | ||
| 71 | while(fgets(buffer, MAX_HEADER_LINE_LENGTH, f)) { | ||
| 72 | printf("%s [%d]", buffer, errno); | ||
| 73 | |||
| 74 | if(buffer[0] == '\n' || (buffer[0] == '\r' && buffer[1] == '\n')) { // either LF or CR/LF (windows) | ||
| 75 | puts("END HEADER\n"); | ||
| 76 | if (!boundary[0]) break; | ||
| 77 | continue; | ||
| 78 | } | ||
| 79 | |||
| 80 | const char header_multipart[] = "Content-Type: multipart/form-data; boundary="; | ||
| 81 | if (!boundary[0] && 0 == strncasecmp(buffer, header_multipart, sizeof(header_multipart) - 1)) { | ||
| 82 | for(int i=sizeof(header_multipart); i<MAX_HEADER_LINE_LENGTH; i++) | ||
| 83 | if(buffer[i] != '-') { | ||
| 84 | strncpy(boundary, &buffer[i], 64); | ||
| 85 | boundary_size = strnlen(boundary, 64); | ||
| 86 | boundary[boundary_size] = '\0'; | ||
| 87 | printf("BOUNDARY[%d]: %s\n", boundary_size, boundary); | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | const char header_disposition[] = "Content-Disposition: form-data; "; | ||
| 93 | if (boundary[0] && 0 == strncasecmp(header_disposition, buffer, sizeof(header_disposition) - 1)) { | ||
| 94 | printf("FFFFFFFFFFFFFFFFFFFFFFF %s\n", buffer); | ||
| 95 | continue; | ||
| 96 | }// else { printf("FUCK: %*s [%d/%ld]\n", (int) sizeof(header_disposition), buffer, strncasecmp(header_disposition, buffer, sizeof(header_disposition)), sizeof(header_disposition)); } | ||
| 97 | |||
| 98 | if(buffer[0] == '-') { // first char minus. could be a new chunk of post data | ||
| 99 | for(int i=1; i<MAX_HEADER_LINE_LENGTH; i++) { | ||
| 100 | if(buffer[i] != '-') { // skip all minus | ||
| 101 | if(0 == strncmp(&buffer[i], boundary, boundary_size)) { | ||
| 102 | printf("\n\n> NEXT CHUNK: %s\n", buffer); | ||
| 103 | i = 0; | ||
| 104 | } | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | } else { | ||
| 109 | printf("%s", buffer); | ||
| 110 | } | ||
| 111 | |||
| 112 | |||
| 113 | // I think another if could now search for "Content-Disposition: form-data; " and store the remaining fields | ||
| 114 | // somewhere, e.g. name="okay"; filename="1.gif". Also there may also be a content-type per chunk, which we | ||
| 115 | // could also add and erase, where I have currently NEXT CHUNK. | ||
| 116 | // After that the text output (printf("%s", buffer)) will only contain content without headers, so that printf | ||
| 117 | // can then be replaced with some fwrite to a memstream and we are done :) | ||
| 118 | } | ||
| 119 | |||
| 120 | puts("> sending answer..."); | ||
| 121 | send_answer(new_socket); | ||
| 122 | puts("> answer sent."); | ||
| 123 | |||
| 71 | 124 | ||
| 72 | return NULL; | 125 | puts("> file closed."); |
| 126 | //close((size_t) new_socket); | ||
| 127 | // pthread_exit(EXIT_SUCCESS); | ||
| 128 | return NULL; | ||
| 73 | } | 129 | } |
| 74 | 130 | ||
| 75 | void serve(int server_fd) | 131 | void serve(int server_fd) |
| @@ -84,17 +140,17 @@ void serve(int server_fd) | |||
| 84 | warn("next: %ld\n", new_socket); | 140 | warn("next: %ld\n", new_socket); |
| 85 | // set non blocking mode... | 141 | // set non blocking mode... |
| 86 | fcntl((size_t) new_socket, F_SETFL, | 142 | fcntl((size_t) new_socket, F_SETFL, |
| 87 | fcntl((size_t) new_socket, F_GETFL) | O_NONBLOCK); | 143 | fcntl((size_t) new_socket, F_GETFL) | O_NONBLOCK); |
| 88 | 144 | ||
| 89 | // next_customer(new_socket); | 145 | next_customer((void*) new_socket); |
| 90 | pthread_t thread_id; | 146 | // pthread_t thread_id; |
| 91 | pthread_create(&thread_id, NULL, next_customer, (void*) new_socket); | 147 | // pthread_create(&thread_id, NULL, next_customer, (void*) new_socket); |
| 92 | pthread_join(thread_id, NULL); | 148 | // pthread_join(thread_id, NULL); |
| 93 | } | 149 | } |
| 94 | } | 150 | } |
| 95 | 151 | ||
| 96 | #define PORT 8080 | 152 | #define PORT 8080 |
| 97 | int main(int argc, char const *argv[]) | 153 | int main(int argc, char const *argv[]) |
| 98 | { | 154 | { |
| 99 | int server_fd; | 155 | int server_fd; |
| 100 | int opt = 1; | 156 | int opt = 1; |
| @@ -110,7 +166,7 @@ int main(int argc, char const *argv[]) | |||
| 110 | ? err(EXIT_FAILURE, "setsockopt failed on socket with fileno %d", server_fd) | 166 | ? err(EXIT_FAILURE, "setsockopt failed on socket with fileno %d", server_fd) |
| 111 | : bind(server_fd, (struct sockaddr*) &address, sizeof(address)) | 167 | : bind(server_fd, (struct sockaddr*) &address, sizeof(address)) |
| 112 | ? err(EXIT_FAILURE, NULL) | 168 | ? err(EXIT_FAILURE, NULL) |
| 113 | : listen(server_fd, 3) | 169 | : listen(server_fd, SOMAXCONN) |
| 114 | ? err(EXIT_FAILURE, NULL) | 170 | ? err(EXIT_FAILURE, NULL) |
| 115 | : serve(server_fd); | 171 | : serve(server_fd); |
| 116 | 172 | ||
