summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Christian Pohle2021-11-28 01:16:40 +0100
committerMax Christian Pohle2021-11-28 01:16:40 +0100
commit7fd1bbc1abafee0f1db19118d127c5bd744f1b67 (patch)
treeaaca6bfd4c88a43ae3abe851c19efc62466eea8b
parent9cf4f824ed6f214f0041bd855f69e75e8fba4bcf (diff)
downloadohmycgi-7fd1bbc1abafee0f1db19118d127c5bd744f1b67.tar.bz2
ohmycgi-7fd1bbc1abafee0f1db19118d127c5bd744f1b67.zip
Refactoring: 2nd step and a working state.
-rw-r--r--cgi.c26
-rw-r--r--http_parser.c109
-rw-r--r--main.c14
3 files changed, 80 insertions, 69 deletions
diff --git a/cgi.c b/cgi.c
index 128eae7..81149af 100644
--- a/cgi.c
+++ b/cgi.c
@@ -42,12 +42,16 @@ static const char * line1 = NULL, * line2 = NULL;
42 42
43int print_on_correct_printer(void * user_data, unsigned flags, cups_dest_t * dest) { 43int print_on_correct_printer(void * user_data, unsigned flags, cups_dest_t * dest) {
44 if(!strstr(dest->name, user_data)) { 44 if(!strstr(dest->name, user_data)) {
45 printf("> Wrong name: %s continue search\n", dest->name); 45 // DEBUG("> Wrong printer name: '%s'; try next printer...\n", dest->name);
46 return 1; 46 return 1;
47 } 47 }
48 48
49 if(!dest || !line1 || !line2) { 49 DEBUG("> Correct printer found: %s\n", dest->name);
50 printf("FAILED: %p %p %p\n", dest, line1, line2); 50
51 if(!dest
52 || !line1
53 || !line2) {
54 DEBUG("> Nothing to print or printer not found: %p %p %p\n", dest, line1, line2);
51 return 1; 55 return 1;
52 } 56 }
53 57
@@ -63,20 +67,22 @@ int print_on_correct_printer(void * user_data, unsigned flags, cups_dest_t * des
63 cups_dinfo_t * info = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, dest); 67 cups_dinfo_t * info = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, dest);
64 68
65 if (cupsCreateDestJob(CUPS_HTTP_DEFAULT, dest, info, &job_id, "My Document", num_options, options) == IPP_STATUS_OK) 69 if (cupsCreateDestJob(CUPS_HTTP_DEFAULT, dest, info, &job_id, "My Document", num_options, options) == IPP_STATUS_OK)
66 printf("Created job: %d\n", job_id); 70 DEBUG("> Created job: %d\n", job_id);
67 else 71 else
68 printf("Unable to create job: %s\n", cupsLastErrorString()); 72 DEBUG("> Unable to create job: %s\n", cupsLastErrorString());
69 73
70 if (cupsStartDestDocument(CUPS_HTTP_DEFAULT, dest, info, job_id, "filename.pdf", CUPS_FORMAT_TEXT, num_options, options, 1) == HTTP_STATUS_CONTINUE) 74 if (cupsStartDestDocument(CUPS_HTTP_DEFAULT, dest, info, job_id, "filename.pdf", CUPS_FORMAT_TEXT, num_options, options, 1) == HTTP_STATUS_CONTINUE)
71 { 75 {
76 DEBUG("> printing label:\n>\t%s\n>\t%s\n", line1, line2);
77
72 cupsWriteRequestData(CUPS_HTTP_DEFAULT, line1, strlen(line1)); 78 cupsWriteRequestData(CUPS_HTTP_DEFAULT, line1, strlen(line1));
73 cupsWriteRequestData(CUPS_HTTP_DEFAULT, "\n", 1); 79 cupsWriteRequestData(CUPS_HTTP_DEFAULT, "\n", 1);
74 cupsWriteRequestData(CUPS_HTTP_DEFAULT, line2, strlen(line2)); 80 cupsWriteRequestData(CUPS_HTTP_DEFAULT, line2, strlen(line2));
75 81
76 if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT, dest, info) == IPP_STATUS_OK) 82 if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT, dest, info) == IPP_STATUS_OK)
77 puts("Document send succeeded."); 83 DEBUG("> Document send succeeded.");
78 else 84 else
79 printf("Document send failed: %s\n", cupsLastErrorString()); 85 DEBUG("> Document send failed: %s\n", cupsLastErrorString());
80 } 86 }
81 return 0; 87 return 0;
82} 88}
@@ -116,16 +122,18 @@ void send_answer(Http_Header * http_header, FILE * f) {
116 print_on_correct_printer, 122 print_on_correct_printer,
117 printer_name 123 printer_name
118 ); 124 );
125
119 line1 = NULL; 126 line1 = NULL;
120 line2 = NULL; 127 line2 = NULL;
121 128
122 send_answer_file(http_header, f); 129 send_answer_file(http_header, f);
123} 130}
124 131
125
126void next_part(Http_Header * http_header, const char * content, size_t content_size) { 132void next_part(Http_Header * http_header, const char * content, size_t content_size) {
127 if(!http_header->content_disposition) 133 if(!http_header->content_disposition) {
134 DEBUG("> No Content-Disposition header found\n");
128 return; 135 return;
136 }
129 137
130 if(strstr(http_header->content_disposition, "name=\"line1\"")) { 138 if(strstr(http_header->content_disposition, "name=\"line1\"")) {
131 line1 = content; 139 line1 = content;
diff --git a/http_parser.c b/http_parser.c
index 30e74c8..03d8d91 100644
--- a/http_parser.c
+++ b/http_parser.c
@@ -54,7 +54,7 @@ static inline char * handle_colon(char ** start, char ** end, char ** search) {
54 return *start; // remember, where name starts, will be important in the newline case 54 return *start; // remember, where name starts, will be important in the newline case
55} 55}
56 56
57static inline void handle_semicolon(char ** start, char ** end, char ** search) { 57static inline char * handle_semicolon(char ** start, char ** end, char ** search) {
58 // find the form-data boundary in the main header 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') 59 *start += strspn(*start, "; "); // remove spaces and semicolons (boundary check implicit; also stops at '\0')
60 60
@@ -63,10 +63,15 @@ static inline void handle_semicolon(char ** start, char ** end, char ** search)
63 { 63 {
64 *end = *end + sizeof(s_multipart_form_data) + 1; 64 *end = *end + sizeof(s_multipart_form_data) + 1;
65 *end += strspn(*end, "-"); 65 *end += strspn(*end, "-");
66 *start = *end;
66 DEBUG("> Boundary found, now looking where it ends...\n"); 67 DEBUG("> Boundary found, now looking where it ends...\n");
68
69 *end += strcspn(*end, "\r\n ");
70 *end[0] = '\0';
67 } 71 }
68 72
69 *search = "\r\n"; // do not search further semicolons 73 *search = "\r\n"; // do not search further semicolons
74 return *start;
70} 75}
71 76
72void parse_http(size_t new_socket, char * request, size_t request_length) { 77void parse_http(size_t new_socket, char * request, size_t request_length) {
@@ -90,12 +95,11 @@ void parse_http(size_t new_socket, char * request, size_t request_length) {
90 size_t matchlen = strspn(end, search); 95 size_t matchlen = strspn(end, search);
91 switch(end[0]) { 96 switch(end[0]) {
92 case ':': 97 case ':':
93 handle_colon(&start, &end, &search); 98 name = handle_colon(&start, &end, &search);
94 name = start;
95 break; 99 break;
96 case ';': 100 case ';':
97 handle_semicolon(&start, &end, &search); 101 http_header.boundary = handle_semicolon(&start, &end, &search);
98 http_header.boundary = end; 102 http_header.boundary_size = end - start;
99 break; 103 break;
100 case '\r': // fallthrough 104 case '\r': // fallthrough
101 case '\n': 105 case '\n':
@@ -123,62 +127,59 @@ void parse_http(size_t new_socket, char * request, size_t request_length) {
123 if (0 == strcasecmp("Content-Disposition", name)) 127 if (0 == strcasecmp("Content-Disposition", name))
124 { http_header.content_disposition = start; } 128 { http_header.content_disposition = start; }
125 } // }}} 129 } // }}}
126 DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start);
127 // {{{ check if a http header ended (e.g. two newlines)
128 if(matchlen > http_header.newline_length) {
129 DEBUG("> END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n", matchlen / http_header.newline_length, http_header.boundary, http_header.boundary_size);
130 end += matchlen;
131
132 // if it was the first header, we calculate the boundary size and expect more headers to come after a boundary
133 if(http_header.boundary && http_header.boundary_size == 0) {
134 DEBUG("================================================================================\n");
135 http_header.boundary_size = strlen(http_header.boundary);
136 // skip the first header and boundary...
137 start = end;
138 start += strspn(start, "-");
139 start += http_header.boundary_size;
140 start += http_header.newline_length;
141 continue;
142 } else {
143 char * content_start = end;
144 while(1)
145 {
146 size_t size_remaining = (size_t) request_length - (end - request) - 1;
147 DEBUG("%ld remaining.\n", size_remaining);
148
149 if(size_remaining <= 0) {
150 DEBUG("> not even the boundary would fit in that what is left.\n");
151 break;
152 }
153
154 if(NULL == (end = memchr((void*) end, '-', size_remaining))) {
155 DEBUG("no further '-' found\n");
156 break;
157 }
158
159 char * content_end = end - http_header.newline_length;
160
161 end += strspn(end, "-");
162 if(0 == strncmp(end, http_header.boundary, http_header.boundary_size)) {
163 size_t file_size = content_end - content_start;
164 DEBUG("> Content ends here, size of the last file is %ld\n", file_size);
165 130
166 content_start[file_size + 1] = '\0'; 131 // {{{ DEBUG
167 next_part(&http_header, content_start, file_size); 132 DEBUG("\033[32m[%ld]> '% 20s' = '%s'\033[0m\n", matchlen, name, start);
168 133 // }}}
169 end += http_header.boundary_size;
170 matchlen = strspn(end, "\r\n");
171 DEBUG("> end is at %p, matchlen is %ld\n", end, matchlen);
172 134
173 search = ":"; 135 // check if a http header ended (e.g. two newlines)
136 if(matchlen > http_header.newline_length) {
137 end += matchlen; // go behind the double line break...
138
139 //{{{ DEBUG
140 DEBUG("> END HEADERS, because there were %d newlines; boundary='%s'[%ld]\n",
141 matchlen / http_header.newline_length,
142 http_header.boundary,
143 http_header.boundary_size
144 ); // }}}
145
146 start = end;
147 for(; ; )
148 {
149 size_t size_remaining = (size_t) request_length - (end - request) - 1;
150
151 // {{{ DEBUG
152 DEBUG("%ld remaining.\n", size_remaining);
153 // }}}
154
155 matchlen = strspn(end, "-");
156 if(0 == strncmp(end + matchlen, http_header.boundary, http_header.boundary_size)) {
157 size_t file_size = end - http_header.newline_length - start;
158 DEBUG("> Content ends here, size of the last file is %ld\n", file_size);
159 start[file_size + 1] = '\0';
160
161 next_part(&http_header, start, file_size);
162
163 end += http_header.boundary_size + matchlen;
164 matchlen = http_header.newline_length;
165 DEBUG("> end is at %p, matchlen is %ld\n", end, matchlen);
166 search = ":";
167 break;
168 } else {
169
170 if(!http_header.boundary
171 || size_remaining <= 0
172 || NULL == (end = memchr((void*) end, '-', size_remaining))) {
173 // {{{ DEBUG
174 DEBUG("EOF reached or no further '-' found\n");
175 // }}}
174 break; 176 break;
175 } else {
176 end = end + 1;
177 } 177 }
178 // end++;
178 } 179 }
179 } 180 }
180 break; 181 break;
181 } // }}} if condition after a header 182 } // if condition after a header
182 } // switch 183 } // switch
183 184
184 if(NULL == end) 185 if(NULL == end)
diff --git a/main.c b/main.c
index 906be15..96cfa67 100644
--- a/main.c
+++ b/main.c
@@ -46,7 +46,7 @@ static int read_everything(FILE * f_r, FILE * output) {
46 continue; 46 continue;
47 } 47 }
48 48
49 fwrite(read_buffer, read_buffer_length, 1, output); 49 fwrite(read_buffer, 1, size, output);
50 50
51 if (read_buffer_length > POST_DATA_MAX_LENGTH) 51 if (read_buffer_length > POST_DATA_MAX_LENGTH)
52 return EXIT_FAILURE; 52 return EXIT_FAILURE;
@@ -67,7 +67,10 @@ static void * answer_request(size_t new_socket) {
67 FILE * output = open_memstream(&output_buffer, &output_buffer_length); 67 FILE * output = open_memstream(&output_buffer, &output_buffer_length);
68 68
69 read_everything(f_r, output); // TODO: catch return value and error handling 69 read_everything(f_r, output); // TODO: catch return value and error handling
70 shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection 70 fflush(output);
71 // shutdown(new_socket, SHUT_RD); // shutdown the reading half of the connection
72
73 DEBUG("output buffer has a length of %ld bytes\n", output_buffer_length);
71 74
72 // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym) 75 // TODO: make parsing function abstract (e.g. parse(...) function point with dlsym)
73 parse_http(new_socket, output_buffer, output_buffer_length); 76 parse_http(new_socket, output_buffer, output_buffer_length);
@@ -80,8 +83,8 @@ static void * answer_request(size_t new_socket) {
80 return NULL; 83 return NULL;
81} 84}
82 85
83
84int become_daemon(const char * name) { 86int become_daemon(const char * name) {
87# ifndef DEBUG // debugging is simpler in foreground mode
85 if(fork()) { 88 if(fork()) {
86 exit(EXIT_SUCCESS); 89 exit(EXIT_SUCCESS);
87 } else { 90 } else {
@@ -90,12 +93,12 @@ int become_daemon(const char * name) {
90 exit(EXIT_SUCCESS); 93 exit(EXIT_SUCCESS);
91 } else { 94 } else {
92 syslog(0, "daemon '%s' is running with pid %d", name, getpid()); 95 syslog(0, "daemon '%s' is running with pid %d", name, getpid());
93 return EXIT_SUCCESS;
94 } 96 }
95 } 97 }
98# endif
99 return EXIT_SUCCESS;
96} 100}
97 101
98
99static int serve(int server_fd) 102static int serve(int server_fd)
100{ 103{
101 struct sockaddr_in address; 104 struct sockaddr_in address;
@@ -129,7 +132,6 @@ int main(const int argc, char const * argv[]) {
129 int port = atoi(argc > 1 ? argv[1] : "8080"); 132 int port = atoi(argc > 1 ? argv[1] : "8080");
130 0 == port ? port = 8080 : port; 133 0 == port ? port = 8080 : port;
131 134
132
133 struct sockaddr_in address = { 135 struct sockaddr_in address = {
134 .sin_family = AF_INET, 136 .sin_family = AF_INET,
135 .sin_addr.s_addr = INADDR_ANY, 137 .sin_addr.s_addr = INADDR_ANY,
..