Пример #1
0
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;
  }
}
Пример #2
0
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;
  }
}