summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Christian Pohle2021-11-27 13:47:24 +0100
committerMax Christian Pohle2021-11-27 13:47:24 +0100
commit9cf4f824ed6f214f0041bd855f69e75e8fba4bcf (patch)
treef52d5b70059b076910baf2eda041cac47569c0a0
parent87451879bf098521db618052d6068ace1dd62492 (diff)
downloadohmycgi-9cf4f824ed6f214f0041bd855f69e75e8fba4bcf.tar.bz2
ohmycgi-9cf4f824ed6f214f0041bd855f69e75e8fba4bcf.zip
Refactoring, stable&functional intermediate state
-rw-r--r--cgi.c16
-rw-r--r--http_parser.c80
-rw-r--r--main.h2
3 files changed, 62 insertions, 36 deletions
diff --git a/cgi.c b/cgi.c
index aa86c9a..128eae7 100644
--- a/cgi.c
+++ b/cgi.c
@@ -81,9 +81,7 @@ int print_on_correct_printer(void * user_data, unsigned flags, cups_dest_t * des
81 return 0; 81 return 0;
82} 82}
83 83
84void send_answer_file(Http_Header * http_header, int fd_socket) { 84void send_answer_file(Http_Header * http_header, FILE * f) {
85
86 FILE * f = fdopen((size_t) fd_socket, "w");
87 fputs("HTTP/1.0 200 OK\n", f); 85 fputs("HTTP/1.0 200 OK\n", f);
88 fputs("content-type: text/html\n\n", f); 86 fputs("content-type: text/html\n\n", f);
89 fflush(f); 87 fflush(f);
@@ -96,23 +94,20 @@ void send_answer_file(Http_Header * http_header, int fd_socket) {
96 for(;;) { 94 for(;;) {
97 read_size = fread(buffer, 1, BUFFER_SIZE, file); 95 read_size = fread(buffer, 1, BUFFER_SIZE, file);
98 fwrite(buffer, 1, read_size, f); 96 fwrite(buffer, 1, read_size, f);
99 fflush(f);
100 if(feof(file)) 97 if(feof(file))
101 break; 98 break;
102 } 99 }
103 } else { 100 } else {
104 if(http_header->url) // TODO: too dangerous to check that here, that is too late.
105 fprintf(f, "could not open file \"%s\"\n", &http_header->url[1]); 101 fprintf(f, "could not open file \"%s\"\n", &http_header->url[1]);
106 } 102 }
107 103
108 fflush(f);
109 fclose(f);
110 return; 104 return;
111} 105}
112 106
113void send_answer(Http_Header * http_header, int fd_socket) { 107void send_answer(Http_Header * http_header, FILE * f) {
108
109 char * printer_name = "Brother_QL-720NW"; // TODO: make configurable
114 110
115 char * printer_name = "Brother_QL-720NW";
116 cupsEnumDests(CUPS_DEST_FLAGS_NONE, 111 cupsEnumDests(CUPS_DEST_FLAGS_NONE,
117 0, 112 0,
118 NULL, 113 NULL,
@@ -124,8 +119,7 @@ void send_answer(Http_Header * http_header, int fd_socket) {
124 line1 = NULL; 119 line1 = NULL;
125 line2 = NULL; 120 line2 = NULL;
126 121
127 http_header->url = "/index.html"; 122 send_answer_file(http_header, f);
128 send_answer_file(http_header, fd_socket);
129} 123}
130 124
131 125
diff --git a/http_parser.c b/http_parser.c
index 05cd094..30e74c8 100644
--- a/http_parser.c
+++ b/http_parser.c
@@ -37,7 +37,47 @@
37 37
38#include "main.h" 38#include "main.h"
39 39
40static inline char * handle_colon(char ** start, char ** end, char ** search) {
41 // HTTP headers and content are separated by an empty line (which is two
42 // newlines), but before that there are pairs of names and values, separated
43 // by a colon, e.g. Content-Type: text/html and this function is called, when
44 // *end reaches a colon.
45
46 *end[0] = '\0'; // remember header 'names' and search for the value
47 (*end)++; // jump over the colon
48
49 if (0 == strcasecmp("Content-Type", *start)) {
50 *search = "\r\n;"; // (more unlikely) also search for a semicolon in Content-Type: [...]; boundary=[...]
51 } else {
52 *search = "\r\n"; // (likely) search for some kind of newline
53 }
54 return *start; // remember, where name starts, will be important in the newline case
55}
56
57static inline void handle_semicolon(char ** start, char ** end, char ** search) {
58 // find the form-data boundary in the main header
59 *start += strspn(*start, "; "); // remove spaces and semicolons (boundary check implicit; also stops at '\0')
60
61 const char s_multipart_form_data[] = "boundary=";
62 if(0 < strcasecmp(*start, s_multipart_form_data))
63 {
64 *end = *end + sizeof(s_multipart_form_data) + 1;
65 *end += strspn(*end, "-");
66 DEBUG("> Boundary found, now looking where it ends...\n");
67 }
68
69 *search = "\r\n"; // do not search further semicolons
70}
71
40void parse_http(size_t new_socket, char * request, size_t request_length) { 72void parse_http(size_t new_socket, char * request, size_t request_length) {
73 // this http parser modifies the input buffer and replaces single characters
74 // with \0-chars to terminate them, but it does not copy strings, because
75 // that would require tedious length checks and would also allow the user
76 // to submit forms with unreasonable long strings in strange places or to
77 // make it shorter: it would make boundary checks necessary for every single
78 // heaer name, value, sub-value and content. This implementation is more
79 // generic and only requires content length bounary checks.
80
41 char * start = request; 81 char * start = request;
42 char * end = NULL; 82 char * end = NULL;
43 char * search = "\r\n"; 83 char * search = "\r\n";
@@ -50,30 +90,12 @@ void parse_http(size_t new_socket, char * request, size_t request_length) {
50 size_t matchlen = strspn(end, search); 90 size_t matchlen = strspn(end, search);
51 switch(end[0]) { 91 switch(end[0]) {
52 case ':': 92 case ':':
53 end[0] = '\0'; // {{{ remember header 'names' and search for the value 93 handle_colon(&start, &end, &search);
54 end++; // jump over the colon 94 name = start;
55 95 break;
56 name = start; // remember, where name starts, will be important in the newline case
57
58 if (0 == strcasecmp("Content-Type", start)) {
59 search = "\r\n;"; // (more unlikely) also search for a semicolon in Content-Type: [...]; boundary=[...]
60 } else {
61 search = "\r\n"; // (likely) search for some kind of newline
62 } // }}}
63 break;
64 case ';': 96 case ';':
65 // {{{ find the form-data boundary in the main header 97 handle_semicolon(&start, &end, &search);
66 start += strspn(start, "; "); // remove spaces and semicolons (boundary check implicit; also stops at '\0') 98 http_header.boundary = end;
67
68 const char s_multipart_form_data[] = "boundary=";
69 if(NULL == http_header.boundary && 0 < strcasecmp(start, s_multipart_form_data))
70 {
71 http_header.boundary = end + sizeof(s_multipart_form_data) + 1;
72 http_header.boundary += strspn(http_header.boundary, "-");
73 DEBUG("> Boundary found, now looking where it ends...\n");
74 search = "\r\n";
75 continue;
76 } /// }}}
77 break; 99 break;
78 case '\r': // fallthrough 100 case '\r': // fallthrough
79 case '\n': 101 case '\n':
@@ -165,8 +187,18 @@ void parse_http(size_t new_socket, char * request, size_t request_length) {
165 start = end + matchlen; 187 start = end + matchlen;
166 } 188 }
167 189
190 // failed to find URL? Use a default to avoid NULL pointer exceptions later
191 if(!http_header.url || http_header.url[0] == '\0' || http_header.url[1] == '\0') {
192 http_header.url = "/index.html";
193 DEBUG("Warning: Request had no URL and is probably invalid: %d", http_header.url[0]);
194 }
195
168 DEBUG("> sending answer...\n"); 196 DEBUG("> sending answer...\n");
169 send_answer(&http_header, new_socket); 197 FILE * f = fdopen((size_t) new_socket, "w");
198 send_answer(&http_header, f);
199
200 fflush(f);
201 fclose(f);
170 DEBUG("> answer sent.\n"); 202 DEBUG("> answer sent.\n");
171} 203}
172 204
diff --git a/main.h b/main.h
index af156f6..826ef47 100644
--- a/main.h
+++ b/main.h
@@ -81,7 +81,7 @@ typedef struct {
81} Http_Header; 81} Http_Header;
82 82
83void next_part(Http_Header * http_header, const char * content, size_t content_size); 83void next_part(Http_Header * http_header, const char * content, size_t content_size);
84void send_answer(Http_Header * http_header, int fd_socket); 84void send_answer(Http_Header * http_header, FILE * socket);
85void parse_http(size_t new_socket, char * request, size_t request_length); 85void parse_http(size_t new_socket, char * request, size_t request_length);
86 86
87// modeline for vim: shiftwidth=2 tabstop=2 number foldmethod=marker foldenable 87// modeline for vim: shiftwidth=2 tabstop=2 number foldmethod=marker foldenable
..