diff options
-rw-r--r-- | cgi.c | 26 | ||||
-rw-r--r-- | http_parser.c | 109 | ||||
-rw-r--r-- | main.c | 14 |
3 files changed, 80 insertions, 69 deletions
@@ -42,12 +42,16 @@ static const char * line1 = NULL, * line2 = NULL; | |||
42 | 42 | ||
43 | int print_on_correct_printer(void * user_data, unsigned flags, cups_dest_t * dest) { | 43 | int 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 | |||
126 | void next_part(Http_Header * http_header, const char * content, size_t content_size) { | 132 | void 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 | ||
57 | static inline void handle_semicolon(char ** start, char ** end, char ** search) { | 57 | static 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 | ||
72 | void parse_http(size_t new_socket, char * request, size_t request_length) { | 77 | void 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) |
@@ -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 | |||
84 | int become_daemon(const char * name) { | 86 | int 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 | |||
99 | static int serve(int server_fd) | 102 | static 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, |