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, | 
