summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--main.c336
2 files changed, 290 insertions, 58 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1f8a372
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
1
2test: main
3 ./main
4
5main: clean
6
7clean:
8 rm -f ./main
9
10%:
11 $(CC) -pthread -g -o $@ $@.c
12
diff --git a/main.c b/main.c
index 6613df0..69ac01e 100644
--- a/main.c
+++ b/main.c
@@ -1,3 +1,5 @@
1#include <asm-generic/errno-base.h>
2#include <asm-generic/errno.h>
1#include <netinet/in.h> 3#include <netinet/in.h>
2#include <stdio.h> 4#include <stdio.h>
3#include <stdio_ext.h> 5#include <stdio_ext.h>
@@ -16,10 +18,7 @@
16#include <pthread.h> 18#include <pthread.h>
17 19
18 20
19 21void send_answer(FILE * f) {
20void send_answer(void * new_socket) {
21 FILE * f = fdopen((size_t) new_socket, "w");
22 puts("> sending answer...");
23 fputs("HTTP/1.0 200 OK\n", f); 22 fputs("HTTP/1.0 200 OK\n", f);
24 fputs("content-type: text/html\n\n", f); 23 fputs("content-type: text/html\n\n", f);
25 fputs("<html>", f); 24 fputs("<html>", f);
@@ -34,13 +33,256 @@ void send_answer(void * new_socket) {
34 fputs("<input type=\"file\" name=\"okay\" value=\"ok\" />", f); 33 fputs("<input type=\"file\" name=\"okay\" value=\"ok\" />", f);
35 fputs("<input type=\"submit\" name=\"okay\" value=\"ok\" />", f); 34 fputs("<input type=\"submit\" name=\"okay\" value=\"ok\" />", f);
36 fputs("</form>", f); 35 fputs("</form>", f);
37 fputs("</html>\n\0", f); 36 fputs("</html>", f);
38 fflush(f); 37}
38
39void * next_customer(size_t new_socket) {
40
41 char * output_buffer = NULL;
42 size_t output_buffer_length = 0;
43 FILE * output = open_memstream(&output_buffer, &output_buffer_length);
44
45 const int read_buffer_length = 10;
46 char read_buffer[read_buffer_length];
47
48 puts("\n\n########################################## Content Reader");
49 FILE * q = fdopen((size_t) new_socket, "r");
50 printf("fd : %p\n", q);
51
52 for(size_t size = -2 ; ; size = fread(read_buffer, read_buffer_length, 1, q)) {
53 if(-2 == size || (-1 == size && EWOULDBLOCK == errno)) {
54 usleep(1000);
55 continue;
56 } else if (1 != size) { // I expect one nmemb of data
57 break;
58 }
59
60 fwrite(read_buffer, read_buffer_length, 1, output);
61 fwrite(read_buffer, read_buffer_length, 1, stdout);
62 }
63 fflush(output);
64
65
66 puts("\n\n########################################## Content Parser");
67 typedef struct {
68 const char * name;
69 const char * value;
70 } NameValue;
71
72 NameValue namevalue[] = {
73 {"Content-Type", NULL},
74 {"Content-Length", NULL}
75 };
76
77 // token parser...
78 const char * boundary = NULL;
79 size_t boundary_length = 0;
80 char * search = NULL;
81 char * key = output_buffer;
82
83 char * saveptr = NULL;
84 char * content_start = NULL;
85 char * content_end = NULL;
86
87 while(1) {
88
89 printf("NEXT ITERATION with search '%s'\n", search);
90
91 for(char *
92 token = strtok_r(NULL == saveptr ? output_buffer : saveptr, NULL == search ? "\n\r" : search, &saveptr);
93 token != NULL;
94 token = strtok_r(NULL, search, &saveptr))
95 {
96
97 if(!search) { // first round: HTTP status code
98 puts("FIRST ITERATION");
99 printf("HTTP sanity check: %s\n", token);
100 search = ":";
101 continue;
102 }
103
104 if(!key) {
105 search = "\r\n"; // we found a key and expect the value to be between here and EOL
106 key = &token[strspn(token, search)]; // also remove leading spaces
107
108 if(0 == strncmp(token, "\n\r\n", 3)
109 || 0 == strncmp(token, "\n\n", 2)) {
110 search = "\r\n";
111 break;
112 }
113 } else { // value
114
115 token += strspn(token, ": ");
116 const char * value = token;
117
118 const char pattern[] = "multipart/form-data; boundary=";
119 if(!boundary && strstr(key, "Content-Type") && strncmp(value, pattern, sizeof(pattern))) {
120 boundary = &value[sizeof(pattern) + strspn(&value[sizeof(pattern)], "-")];
121 boundary_length = strlen(boundary);
122 printf("> [!] boundary detected '%s' ", boundary);
123 }
124
125 for(int i=0; i < sizeof(namevalue) / sizeof(NameValue); i++) {
126 // printf("next name: %s\n", namevalue[i].name);
127 if(NULL == namevalue[i].value && 0 == strcasecmp(namevalue[i].name, key)) {
128 namevalue[i].value = value;
129 break;
130 }
131 }
132
133 printf("> [%ld] \"%s\" :: \"%s\"\n", key - output_buffer, key, value); fflush(stdout);
134
135 search = ":";
136 key = NULL;
137 }
138 }
139
140 if(!key)
141 break;
142 // printf("We are now here: %ld\n", key - output_buffer);
143 printf("We are now here: %s\n", key);
144
145 // jump over the content...
146 content_start = key;
147 while((key = memchr(key, '\n', output_buffer_length - (key - output_buffer)))) {
148 if(!key) {
149 warnx("out at %p\n", key);
150 break;
151 } else {
152 key++;
153 }
154
155 if(key[0] == '-') {
156 if(0 == strncmp(&key[strspn(key, "-")], boundary, boundary_length)) {
157 puts("GEIL1");
158
159 if(key[-1] == '\n') key--;
160 if(key[-1] == '\r') key--;
161
162 content_end = key;
163 key += strspn(key, "\r\n-");
164 key += boundary_length;
165 key += strspn(key, "\r\n");
166 saveptr = key;
167 key = NULL;
168 search = ":";
169 break;
170 }
171 }
172 }
173
174 printf("content is %p - %p = %ld in size\n", content_end, content_start, content_end - content_start);
175 if(content_end - content_start > 1000) {
176 FILE * f_w = fopen("/tmp/test.gif", "w");
177 fwrite(content_start, content_end - content_start, 1, f_w);
178 fclose(f_w);
179 puts("FILE WRITTEN");
180 }
181
182 // printf("We have gone to %ld\n", key - output_buffer); fflush(stdout);
183 if(key && key[0] == '\0') // final boundary reached?
184 break;
185
186 // usleep(100000);
187 }
188
189
190 puts("> sending answer...");
191 FILE * f_w = fdopen((size_t) new_socket, "w");
192 send_answer(f_w);
193
194 fclose(f_w);
195 fclose(q);
39 puts("> answer sent."); 196 puts("> answer sent.");
40 fclose(f); 197
198 printf("still in knowledge of out boundary: %s\n", namevalue[0].value);
199
200 return NULL;
41} 201}
42 202
43 203
204
205int serve(int server_fd)
206{
207 struct sockaddr_in address;
208 socklen_t address_len = sizeof(address);
209 warnx("waiting for connections on server file descriptor %d", server_fd);
210
211 size_t new_socket = -1;
212 while(-1 !=
213 (new_socket = accept(server_fd,
214 (struct sockaddr*) &address,
215 &address_len)))
216 {
217 warnx("> Client %ld is connected via port %d", new_socket, address.sin_port);
218
219 // set non blocking mode...
220 fcntl((size_t) new_socket, F_SETFL,
221 fcntl((size_t) new_socket, F_GETFL) | O_NONBLOCK);
222
223 next_customer(new_socket);
224
225 /*
226 if(fork()) {
227 close(new_socket);
228 } else {
229 close(server_fd); // give the server free
230 next_customer(new_socket);
231 shutdown(new_socket, SHUT_RDWR);
232 exit(0);
233 }
234 */
235
236 // pthread_t thread_id;
237 // pthread_create(&thread_id, NULL, next_customer, (void*) new_socket);
238 // pthread_join(thread_id, NULL);
239 }
240
241 err(errno, "error serving");
242}
243
244#define PORT 8080
245int main(int argc, char const *argv[])
246{
247 int server_fd = -1, opt = 1;
248
249 struct sockaddr_in address = {
250 .sin_family = AF_INET,
251 .sin_addr.s_addr = INADDR_ANY,
252 .sin_port = htons(PORT)
253 };
254
255 // I <3 C
256 0 == (server_fd = socket(AF_INET, SOCK_STREAM, 0))
257 ? err(errno, NULL)
258 : setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))
259 ? err(errno, "setsockopt failed on socket with fileno %d", server_fd)
260 : bind(server_fd, (struct sockaddr*) &address, sizeof(address))
261 ? err(errno, NULL)
262 : listen(server_fd, SOMAXCONN)
263 ? err(errno, NULL)
264 : serve(server_fd)
265 ? err(errno, NULL)
266 : exit(EXIT_SUCCESS)
267 ;
268 return EXIT_FAILURE;
269}
270
271// void * next_customer_old(int new_socket)
272// {
273// char *hello = "Hello from server";
274// char buffer[1024] = {0};
275// int valread = read(new_socket, buffer, 1024);
276// printf("%s %d\n", buffer, valread);
277//
278// send(new_socket, hello, strlen(hello), 0);
279//
280// printf("Hello message sent\n");
281// return NULL;
282// }
283
284// IDEA ...
285//
44// #define FOREACH_HEADER(HEADER) \ 286// #define FOREACH_HEADER(HEADER) \
45// HEADER("Content-Type: multipart/form-data; boundary=") 287// HEADER("Content-Type: multipart/form-data; boundary=")
46// #define GENERATE_HEADERS(H) sizeof(H), H 288// #define GENERATE_HEADERS(H) sizeof(H), H
@@ -53,10 +295,37 @@ void send_answer(void * new_socket) {
53// const length_value headers[] = { 295// const length_value headers[] = {
54// FOREACH_HEADER(GENERATE_HEADERS) 296// FOREACH_HEADER(GENERATE_HEADERS)
55// }; 297// };
298//
56 299
57 300
301// READ WITH recv ...
302 /*
303 for(size_t size = -1 ; ; (size = recv(new_socket, read_buffer, read_buffer_length, 0))) {
304 if(-1 == size) {
305 usleep(10000);
306 printf("size: %ld\n", size);
307 if(EWOULDBLOCK == errno){
308 continue;
309 } else if (size == 0 || size < read_buffer_length) {
310 break;
311 }
312 } else {
313 read_buffer[size] = '\0';
314
315 fwrite(read_buffer, size, 1, output);
316 fwrite(read_buffer, size, 1, stdout);
317
318 // if(output_buffer_length > 4
319 // && (strspn(&output_buffer[output_buffer_length - 2], "\n") == 2
320 // || strspn(&output_buffer[output_buffer_length - 4], "\r\n") == 4))
321 // break;
322 }
323 }*/
324
325
326// fully working implementation...
327/*
58void * next_customer(void * new_socket) { 328void * next_customer(void * new_socket) {
59 if (new_socket == 0) return NULL;
60 329
61 const int MAX_HEADER_LINE_LENGTH = 1024; 330 const int MAX_HEADER_LINE_LENGTH = 1024;
62 const int MAX_BOUNDARY_LENGTH = 64; 331 const int MAX_BOUNDARY_LENGTH = 64;
@@ -151,56 +420,7 @@ void * next_customer(void * new_socket) {
151 send_answer(new_socket); 420 send_answer(new_socket);
152 puts("> answer sent."); 421 puts("> answer sent.");
153 422
154
155 puts("> file closed.");
156 //close((size_t) new_socket);
157 // pthread_exit(EXIT_SUCCESS);
158 return NULL; 423 return NULL;
159} 424}
160 425*/
161void serve(int server_fd)
162{
163 struct sockaddr_in address;
164 int addrlen = sizeof(address);
165 warn("waiting for connections on %d", server_fd);
166
167 for(size_t new_socket = 0
168 ; 1 ; new_socket=accept(server_fd, (struct sockaddr*) &address, (socklen_t*) &addrlen))
169 {
170 warn("next: %ld\n", new_socket);
171 // set non blocking mode...
172 fcntl((size_t) new_socket, F_SETFL,
173 fcntl((size_t) new_socket, F_GETFL) | O_NONBLOCK);
174
175 next_customer((void*) new_socket);
176 // pthread_t thread_id;
177 // pthread_create(&thread_id, NULL, next_customer, (void*) new_socket);
178 // pthread_join(thread_id, NULL);
179 }
180}
181
182#define PORT 8080
183int main(int argc, char const *argv[])
184{
185 int server_fd;
186 int opt = 1;
187
188 struct sockaddr_in address;
189 address.sin_family = AF_INET;
190 address.sin_addr.s_addr = INADDR_ANY;
191 address.sin_port = htons(PORT);
192
193 0 == (server_fd = socket(AF_INET, SOCK_STREAM, 0))
194 ? err(errno, NULL)
195 : setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))
196 ? err(errno, "setsockopt failed on socket with fileno %d", server_fd)
197 : bind(server_fd, (struct sockaddr*) &address, sizeof(address))
198 ? err(errno, NULL)
199 : listen(server_fd, SOMAXCONN)
200 ? err(errno, NULL)
201 : serve(server_fd);
202
203 return 0;
204}
205
206// vim: shiftwidth=2 tabstop=2 number 426// vim: shiftwidth=2 tabstop=2 number
..