diff options
-rw-r--r-- | main.c | 178 |
1 files changed, 95 insertions, 83 deletions
@@ -54,12 +54,16 @@ void read_everything(FILE * f_r, FILE * output) { | |||
54 | if(-2 == size || (-1 == size && EWOULDBLOCK == errno)) { | 54 | if(-2 == size || (-1 == size && EWOULDBLOCK == errno)) { |
55 | usleep(EWOULDBLOCK_DELAY); // try again a little later | 55 | usleep(EWOULDBLOCK_DELAY); // try again a little later |
56 | continue; | 56 | continue; |
57 | } else if (1 != size) { // I expect one nmemb of data | ||
58 | break; | ||
59 | } | 57 | } |
60 | 58 | ||
61 | fwrite(read_buffer, read_buffer_length, 1, output); | 59 | fwrite(read_buffer, read_buffer_length, 1, output); |
60 | fwrite(read_buffer, read_buffer_length, 1, stdout); | ||
61 | |||
62 | if (1 != size) { // I expect one nmemb of data | ||
63 | break; | ||
64 | } | ||
62 | } | 65 | } |
66 | fflush(stdout); | ||
63 | fflush(output); | 67 | fflush(output); |
64 | } | 68 | } |
65 | 69 | ||
@@ -83,6 +87,14 @@ void header_next(const char * key, const char * value) { | |||
83 | } | 87 | } |
84 | } | 88 | } |
85 | 89 | ||
90 | typedef struct { | ||
91 | int newline_length; // lenght of one newline in bytes (\n has 1, CR/LF has 2) | ||
92 | char * method; | ||
93 | char * boundary; | ||
94 | char * content_type; | ||
95 | char * content_disposition; | ||
96 | } Http_Header; | ||
97 | |||
86 | void * next_customer(size_t new_socket) { | 98 | void * next_customer(size_t new_socket) { |
87 | FILE * f_r = fdopen((size_t) new_socket, "r"); | 99 | FILE * f_r = fdopen((size_t) new_socket, "r"); |
88 | FILE * f_w = fdopen((size_t) new_socket, "w"); | 100 | FILE * f_w = fdopen((size_t) new_socket, "w"); |
@@ -93,111 +105,111 @@ void * next_customer(size_t new_socket) { | |||
93 | 105 | ||
94 | verbose("\n\n########################################## Content Reader [%d]\n", f_r); | 106 | verbose("\n\n########################################## Content Reader [%d]\n", f_r); |
95 | read_everything(f_r, output); | 107 | read_everything(f_r, output); |
96 | verbose("\n\n########################################## Content Parser"); | 108 | verbose("\n\n########################################## Content Parser\n"); |
97 | 109 | ||
98 | 110 | ||
99 | // token parser... | 111 | // token parser... |
100 | const char * boundary = NULL; | ||
101 | size_t boundary_length = 0; | ||
102 | char * search = NULL; | ||
103 | char * key = output_buffer; | 112 | char * key = output_buffer; |
104 | 113 | ||
105 | char * saveptr = NULL; | 114 | char * saveptr = NULL; |
106 | char * content_start = NULL; | 115 | char * content_start = NULL; |
107 | char * content_end = NULL; | 116 | char * content_end = NULL; |
108 | 117 | ||
109 | while(key ? key[0] != '\0' : 1) { | 118 | char * start = output_buffer; |
110 | verbose("> [!] Next iteration with search '%s'\n", search); | 119 | char * end; |
111 | for(char * | 120 | char * search = "\r\n"; |
112 | token = strtok_r(NULL == saveptr ? output_buffer : saveptr, NULL == search ? "\n\r" : search, &saveptr); | 121 | |
113 | token != NULL; | 122 | Http_Header http_header; |
114 | token = strtok_r(NULL, search, &saveptr)) | 123 | http_header.newline_length = 1; |
115 | { | 124 | http_header.method = NULL; |
116 | 125 | http_header.boundary = NULL; | |
117 | if(!search) { // first round: HTTP status code | 126 | http_header.content_disposition = NULL; |
118 | verbose("> First Iteration: HTTP sanity check of: %s\n", token); | 127 | http_header.content_type = NULL; |
119 | search = ":"; | 128 | |
120 | continue; | 129 | char * name = NULL; |
121 | } | 130 | while(NULL != (end = strpbrk(start, search))) { |
122 | 131 | ||
123 | if(!key) { | 132 | size_t matchlen = strspn(end, search); |
124 | search = "\r\n"; // we found a key and expect the value to be between here and EOL | 133 | switch(end[0]) { |
125 | key = &token[strspn(token, search)]; // also remove leading spaces | 134 | case ':': |
135 | end[0] = '\0'; | ||
136 | end++; | ||
126 | 137 | ||
127 | if(0 == strncmp(token, "\n\r\n", 3) | 138 | name = start; |
128 | || 0 == strncmp(token, "\n\n", 2)) { | 139 | |
140 | if (0 == strcasecmp("Content-Type", start)) { | ||
141 | search = "\r\n;"; | ||
142 | } else { | ||
129 | search = "\r\n"; | 143 | search = "\r\n"; |
144 | } | ||
145 | break; | ||
146 | case ';': | ||
147 | { | ||
148 | start += strspn(start, "; "); | ||
149 | |||
150 | const char s_multipart_form_data[] = "boundary="; | ||
151 | if(NULL == http_header.boundary && 0 < strcasecmp(start, s_multipart_form_data)) | ||
152 | { | ||
153 | http_header.boundary = end + sizeof(s_multipart_form_data) + 1; | ||
154 | http_header.boundary += strspn(http_header.boundary, "-"); | ||
155 | // verbose("GESCHAFFT %s QQQQ %s\n", http_header.boundary, end); | ||
156 | search = "\r\n"; | ||
157 | continue; | ||
158 | } | ||
130 | break; | 159 | break; |
131 | } | 160 | } |
132 | } else { // value | 161 | case '\r': // fallthrough |
133 | 162 | case '\n': | |
134 | token += strspn(token, ": "); | 163 | end[0] = '\0'; |
135 | const char * value = token; | 164 | search = ":"; // we will continue to search for headers |
136 | 165 | ||
137 | const char pattern[] = "multipart/form-data; boundary="; | 166 | |
138 | if(!boundary && strstr(key, "Content-Type") && strncmp(value, pattern, sizeof(pattern))) { | 167 | if(NULL == name) { |
139 | boundary = &value[sizeof(pattern) + strspn(&value[sizeof(pattern)], "-")]; | 168 | if(NULL == http_header.method) { |
140 | boundary_length = strlen(boundary); | 169 | verbose("[%ld]> HTTP REQUEST LINE :: %s \n", matchlen, start); |
141 | verbose("> [!] boundary detected '%s' ", boundary); | 170 | http_header.method = start; |
171 | http_header.newline_length = matchlen; | ||
172 | } else { | ||
173 | verbose("[...]\n"); // if we want to intentially skip something, we land here by setting name = NUL; | ||
174 | break; | ||
175 | } | ||
176 | } else { // we know that name is not NULL and can work with it | ||
177 | if (0 == strcasecmp("Content-Disposition", name)) | ||
178 | { http_header.content_disposition = start; } | ||
142 | } | 179 | } |
143 | 180 | ||
144 | header_next(key, value); | 181 | verbose("\033[0;32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start); |
145 | |||
146 | verbose("> [%ld] \"%s\" :: \"%s\"\n", key - output_buffer, key, value); fflush(stdout); | ||
147 | 182 | ||
148 | search = ":"; | 183 | if(matchlen > http_header.newline_length) { |
149 | key = NULL; | 184 | verbose("END HEADERS, boundary='%s'\n", http_header.boundary); |
150 | } | 185 | // start = strstr(end, http_header.boundary); |
151 | } | 186 | search = "-"; |
152 | 187 | } | |
153 | if(!key) | ||
154 | break; | ||
155 | // printf("We are now here: %ld\n", key - output_buffer); | ||
156 | verbose("We are now here: %s\n", key); | ||
157 | |||
158 | // jump over the content... | ||
159 | content_start = key; | ||
160 | while((key = memchr(key, '\n', output_buffer_length - (key - output_buffer)))) { | ||
161 | if(!key) { | ||
162 | verbose("out at %p\n", key); | ||
163 | break; | 188 | break; |
164 | } else { | 189 | case '-': |
165 | key++; | 190 | { |
166 | } | 191 | char * content_start = end; |
167 | 192 | content_start += strspn(content_start, "-"); | |
168 | if(key[0] == '-') { | 193 | // verbose("CONTENT: %s\n", content_start); |
169 | if(0 == strncmp(&key[strspn(key, "-")], boundary, boundary_length)) { | 194 | if(0 <= strcmp(content_start, http_header.boundary)) { |
170 | verbose("> boundary found."); | 195 | verbose("MATCH\n"); |
171 | 196 | search = "\r\n"; | |
172 | if(key[-1] == '\n') key--; | 197 | start = content_start + strlen(http_header.boundary); |
173 | if(key[-1] == '\r') key--; | 198 | name = NULL; |
174 | 199 | continue; | |
175 | content_end = key; | 200 | } else { |
176 | key += strspn(key, "\r\n-"); | 201 | verbose("NO MATCH\n"); |
177 | key += boundary_length; | 202 | } |
178 | key += strspn(key, "\r\n"); | ||
179 | saveptr = key; | ||
180 | key = NULL; | ||
181 | search = ":"; | ||
182 | break; | 203 | break; |
183 | } | 204 | } |
184 | } | ||
185 | } | 205 | } |
186 | 206 | ||
187 | verbose("content is %p - %p = %ld in size\n", content_end, content_start, content_end - content_start); | 207 | start = end + matchlen; |
188 | if(content_end - content_start > 1000) { | 208 | } |
189 | FILE * f_w = fopen("/tmp/test.gif", "w"); | ||
190 | fwrite(content_start, content_end - content_start, 1, f_w); | ||
191 | fclose(f_w); | ||
192 | puts("FILE WRITTEN"); | ||
193 | } | ||
194 | 209 | ||
195 | // printf("We have gone to %ld\n", key - output_buffer); fflush(stdout); | 210 | if(http_header.boundary) |
196 | if(key && key[0] == '\0') // final boundary reached? | 211 | verbose("http-boundary: %s", http_header.boundary); |
197 | break; | ||
198 | 212 | ||
199 | // usleep(100000); | ||
200 | } | ||
201 | 213 | ||
202 | verbose("> sending answer..."); | 214 | verbose("> sending answer..."); |
203 | send_answer(f_w); | 215 | send_answer(f_w); |