int mpp_process_char(parse_ctx *ctx, char c) { // trap errors first if (ctx->meta_pos >= META_BUFFER_SIZE - 1 || ctx->data_pos >= DATA_BUFFER_SIZE - 1 || ctx->unknown_pos >= UNKNOWN_BUFFER_SIZE - 1) { // fprintf(stdout, "Buffer limit reached meta[%d] data[%d] unknown[%d]\n", ctx->meta_pos, ctx->data_pos, ctx->unknown_pos); return 1; } // discard leading new lines if ( ctx->reading_meta == 0 && ctx->reading_data == 0 && ctx->reading_unknown == 0 ) { if ( c == '\n' || c == '\r' ) { return 0; } else { // fprintf(stdout, "Started parse of data\n"); ctx->reading_meta = 1; ctx->meta_buffer[ctx->meta_pos] = c; ctx->meta_pos++; return 0; } } // hit a new line char if ( c == '\n' ) { // fprintf(stdout, "newline\n"); if ( ctx->reading_meta == 1 ) { if ( ctx->last_was_newline == 1 ) { // fprintf(stdout, "\n double newline end of meta \n\n"); ctx->last_was_newline = 0; ctx->reading_meta = 0; ctx->reading_data = 1; discard_meta(ctx); } else { ctx->meta_buffer[ctx->meta_pos] = 0; process_meta_newline(ctx); ctx->last_was_newline = 1; } return 0; } else if ( ctx->reading_unknown == 1 ) { // fprintf(stdout, "newline in unknown_state always wrong [%d]\n", c); ctx->unknown_buffer[ctx->unknown_pos] = c; ctx->unknown_pos++; flush_data_buffer(ctx); flush_unknown_buffer(ctx); ctx->reading_unknown = 0; ctx->reading_data = 1; return 0; } else if ( ctx->reading_data == 1 ) { // fprintf(stdout, "enter unknown state\n"); ctx->data_buffer[ctx->data_pos] = c; ctx->data_pos++; ctx->reading_unknown = 1 ; return 0; } return -1; //bug } if ( c == '\r' ) { if ( ctx->reading_meta == 1 ) { return 0; } } // any other char c ctx->last_was_newline = 0; if ( ctx->reading_unknown == 1 ) { // fprintf(stdout, "reading_unkown"); int ret = match_boundary(ctx, c); if ( ret == 0 ) { // matching ctx->unknown_buffer[ctx->unknown_pos] = c; ctx->unknown_pos++; return 0; } else if ( ret == 1 ) { // full match // fprintf(stdout, "Match!\n"); // discard CRLF we added, this works for only LF provided there was not a natural CR first (spec requries CRLF anyway) if (ctx->data_buffer[ctx->data_pos -1] == '\n') ctx->data_pos--; if (ctx->data_buffer[ctx->data_pos -1] == '\r') ctx->data_pos--; ctx->data_buffer[ctx->data_pos] = 0; // string terminate (not needed except for debug) int ret = flush_data_buffer(ctx); ctx->unknown_buffer[0] = 0; ctx->unknown_pos = 0; ctx->reading_file = 0; ctx->reading_unknown = 0; ctx->reading_data = 0; ctx->reading_meta = 1; return ret; } else { // fprintf(stdout, "False alarm!!\n"); ctx->unknown_buffer[ctx->unknown_pos] = c; ctx->unknown_pos++; int ret = flush_data_buffer(ctx); flush_unknown_buffer(ctx); ctx->reading_unknown = 0; return ret; } } // fill the buffers else if (ctx->reading_meta == 1) { // fprintf(stdout, "filling meta [%d]\n" , ctx->meta_pos); ctx->meta_buffer[ctx->meta_pos] = c; ctx->meta_pos++; return 0; } else if (ctx->reading_data == 1) { int ret = 0; if (ctx->data_pos == DATA_BUFFER_SIZE - 2) { // -2 for CRLF that can end up in the data_buffer // flush the data_buffer, it is full ret = flush_data_buffer(ctx); } ctx->data_buffer[ctx->data_pos] = c; ctx->data_pos++; return ret; } else { // fprintf(stdout, "bug\n"); return -2; } }
void cgi_mpfd_t::parse_guts () { abuf_stat_t r = ABUF_OK; str dummy; bool inc; while (r == ABUF_OK) { OKDBG4(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts loop " "r=%d, state=%d", int (r), int (state)); inc = true; switch (state) { case MPFD_START: r = match_boundary (); break; case MPFD_EOL0: r = require_crlf (); break; case MPFD_KEY: r = gobble_crlf (); if (r == ABUF_OK) { if (to_start) { state = MPFD_START; to_start = false; } else state = MPFD_SEARCH; inc = false; } else if (r == ABUF_NOMATCH) { r = delimit_key (&mpfd_key); if (r == ABUF_OK) kt = mpfd_ktmap.lookup (mpfd_key); } // else a WAIT or an EOF in gobble_crlf break; case MPFD_SPC: r = abuf->skip_hws (1); cdp.reset (); break; case MPFD_VALUE: if (kt == MPFD_DISPOSITION) { OKDBG3(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts branch to nested " "content disposition parser"); cdp.parse (wrap (this, &cgi_mpfd_t::ext_parse_cb)); OKDBG3(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts return due to " "content disposition parser"); return; } else if (kt == MPFD_TYPE) { r = delimit_val (&content_typ); if (r == ABUF_OK) { if (multipart_rxx.match (content_typ)) { add_boundary (multipart_rxx[1]); to_start = true; } } } else { r = delimit_val (&dummy); } break; case MPFD_EOL1A: r = require_crlf (); break; case MPFD_EOL1B: if (kt == MPFD_DISPOSITION) { if (cdp.typ == CONTDISP_FORMDAT) { cgi_key = cdp.name; filename = cdp.filename; attach = filename; } else if (cdp.typ == CONTDISP_ATTACH) { filename = cdp.filename; attach = true; } else { r = ABUF_PARSE_ERR; } } state = MPFD_KEY; inc = false; break; case MPFD_SEARCH: r = match_boundary (&dat); if (r == ABUF_OK) { if (cgi_key) { if (attach) finsert (cgi_key, cgi_file_t (filename, content_typ, dat)); else insert (cgi_key, dat); cgi_key = NULL; } // in this case, no more boundaries } else if (r == ABUF_PARSE_ERR) { r = ABUF_OK; state = MPFD_EOF; inc = false; } break; case MPFD_SEARCH2: r = parse_2dash (); if (r == ABUF_OK) { remove_boundary (); nxt_state = MPFD_SEARCH; } else if (r == ABUF_NOMATCH) { r = ABUF_OK; nxt_state = MPFD_KEY; } break; case MPFD_SEARCH3: r = require_crlf (); if (r == ABUF_OK) { state = nxt_state; inc = false; } break; case MPFD_EOF: r = abuf->skip_ws (); break; default: break; } if (r == ABUF_OK && inc) MPFD_INC_STATE; } OKDBG4(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts exit loop " "r=%d, state=%d", int (r), int (state)); switch (r) { case ABUF_EOF: int rc; if (state == MPFD_EOF) { rc = HTTP_OK; } else { rc = HTTP_UNEXPECTED_EOF; warn ("mpfd EOF in state %d after %d bytes read\n", int (state), abuf ? abuf->get_ccnt () : -1); } finish_parse (rc); break; case ABUF_PARSE_ERR: finish_parse (HTTP_BAD_REQUEST); break; default: break; } }