diff options
Diffstat (limited to 'main.c')
-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 | ||