Example #1
0
/**
 * Parse and unescape the arguments given by the client
 * as part of the HTTP request URI.
 *
 * @param kind header kind to pass to @a cb
 * @param connection connection to add headers to
 * @param[in,out] args argument URI string (after "?" in URI),
 *        clobbered in the process!
 * @param cb function to call on each key-value pair found
 * @param[out] num_headers set to the number of headers found
 * @return #MHD_NO on failure (@a cb returned #MHD_NO),
 *         #MHD_YES for success (parsing succeeded, @a cb always
 *                               returned #MHD_YES)
 */
int
MHD_parse_arguments_ (struct MHD_Connection *connection,
		      enum MHD_ValueKind kind,
		      char *args,
		      MHD_ArgumentIterator_ cb,
		      unsigned int *num_headers)
{
  struct MHD_Daemon *daemon = connection->daemon;
  char *equals;
  char *amper;

  *num_headers = 0;
  while ( (NULL != args) &&
	  ('\0' != args[0]) )
    {
      size_t key_len;
      size_t value_len;
      equals = strchr (args, '=');
      amper = strchr (args, '&');
      if (NULL == amper)
	{
	  /* last argument */
	  if (NULL == equals)
	    {
	      /* last argument, without '=' */
              MHD_unescape_plus (args);
	      key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
			                           connection,
                                                   args);
	      if (MHD_YES != cb (connection,
				 args,
				 key_len,
				 NULL,
				 0,
				 kind))
		return MHD_NO;
	      (*num_headers)++;
	      break;
	    }
	  /* got 'foo=bar' */
	  equals[0] = '\0';
	  equals++;
          MHD_unescape_plus (args);
	  key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                               connection,
                                               args);
          MHD_unescape_plus (equals);
	  value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                                 connection,
                                                 equals);
	  if (MHD_YES != cb (connection,
			     args,
			     key_len,
			     equals,
			     value_len,
			     kind))
	    return MHD_NO;
	  (*num_headers)++;
	  break;
	}
      /* amper is non-NULL here */
      amper[0] = '\0';
      amper++;
      if ( (NULL == equals) ||
	   (equals >= amper) )
	{
	  /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value */
          MHD_unescape_plus (args);
          key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                               connection,
                                               args);
	  if (MHD_YES != cb (connection,
			     args,
			     key_len,
			     NULL,
			     0,
			     kind))
	    return MHD_NO;
	  /* continue with 'bar' */
	  (*num_headers)++;
	  args = amper;
	  continue;
	}
      /* equals and amper are non-NULL here, and equals < amper,
	 so we got regular 'foo=value&bar...'-kind of argument */
      equals[0] = '\0';
      equals++;
      MHD_unescape_plus (args);
      key_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                           connection,
                                           args);
      MHD_unescape_plus (equals);
      value_len = daemon->unescape_callback (daemon->unescape_callback_cls,
                                             connection,
                                             equals);
      if (MHD_YES != cb (connection,
			 args,
			 key_len,
			 equals,
			 value_len,
			 kind))
        return MHD_NO;
      (*num_headers)++;
      args = amper;
    }
  return MHD_YES;
}
Example #2
0
/**
 * Process url-encoded POST data.
 *
 * @param pp post processor context
 * @param post_data upload data
 * @param post_data_len number of bytes in @a post_data
 * @return #MHD_YES on success, #MHD_NO if there was an error processing the data
 */
static int
post_process_urlencoded (struct MHD_PostProcessor *pp,
                         const char *post_data,
			 size_t post_data_len)
{
  size_t equals;
  size_t amper;
  size_t poff;
  size_t xoff;
  size_t delta;
  int end_of_value_found;
  char *buf;
  char xbuf[XBUF_SIZE + 1];

  buf = (char *) &pp[1];
  poff = 0;
  while (poff < post_data_len)
    {
      switch (pp->state)
        {
        case PP_Error:
          return MHD_NO;
        case PP_Done:
          /* did not expect to receive more data */
          pp->state = PP_Error;
          return MHD_NO;
        case PP_Init:
          equals = 0;
          while ((equals + poff < post_data_len) &&
                 (post_data[equals + poff] != '='))
            equals++;
          if (equals + pp->buffer_pos > pp->buffer_size)
            {
              pp->state = PP_Error;     /* out of memory */
              return MHD_NO;
            }
          memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
          pp->buffer_pos += equals;
          if (equals + poff == post_data_len)
            return MHD_YES;     /* no '=' yet */
          buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
          pp->buffer_pos = 0;   /* reset for next key */
	  MHD_unescape_plus (buf);
          MHD_http_unescape (buf);
          poff += equals + 1;
          pp->state = PP_ProcessValue;
          pp->value_offset = 0;
          break;
        case PP_ProcessValue:
          /* obtain rest of value from previous iteration */
          memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
          xoff = pp->xbuf_pos;
          pp->xbuf_pos = 0;

          /* find last position in input buffer that is part of the value */
          amper = 0;
          while ((amper + poff < post_data_len) &&
                 (amper < XBUF_SIZE) &&
                 (post_data[amper + poff] != '&') &&
                 (post_data[amper + poff] != '\n') &&
                 (post_data[amper + poff] != '\r'))
            amper++;
          end_of_value_found = ((amper + poff < post_data_len) &&
                                ((post_data[amper + poff] == '&') ||
                                 (post_data[amper + poff] == '\n') ||
                                 (post_data[amper + poff] == '\r')));
          /* compute delta, the maximum number of bytes that we will be able to
             process right now (either amper-limited of xbuf-size limited) */
          delta = amper;
          if (delta > XBUF_SIZE - xoff)
            delta = XBUF_SIZE - xoff;

          /* move input into processing buffer */
          memcpy (&xbuf[xoff], &post_data[poff], delta);
          xoff += delta;
          poff += delta;

          /* find if escape sequence is at the end of the processing buffer;
             if so, exclude those from processing (reduce delta to point at
             end of processed region) */
          delta = xoff;
          if ((delta > 0) && (xbuf[delta - 1] == '%'))
            delta--;
          else if ((delta > 1) && (xbuf[delta - 2] == '%'))
            delta -= 2;

          /* if we have an incomplete escape sequence, save it to
             pp->xbuf for later */
          if (delta < xoff)
            {
              memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
              pp->xbuf_pos = xoff - delta;
              xoff = delta;
            }

          /* If we have nothing to do (delta == 0) and
             not just because the value is empty (are
             waiting for more data), go for next iteration */
          if ((xoff == 0) && (poff == post_data_len))
            continue;

          /* unescape */
          xbuf[xoff] = '\0';    /* 0-terminate in preparation */
	  MHD_unescape_plus (xbuf);
          xoff = MHD_http_unescape (xbuf);
          /* finally: call application! */
	  pp->must_ikvi = MHD_NO;
          if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1],    /* key */
                                  NULL, NULL, NULL, xbuf, pp->value_offset,
                                  xoff))
            {
              pp->state = PP_Error;
              return MHD_NO;
            }
          pp->value_offset += xoff;

          /* are we done with the value? */
          if (end_of_value_found)
            {
              /* we found the end of the value! */
              if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
                {
                  pp->state = PP_ExpectNewLine;
                }
              else if (post_data[poff] == '&')
                {
                  poff++;       /* skip '&' */
                  pp->state = PP_Init;
                }
            }
          break;
        case PP_ExpectNewLine:
          if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
            {
              poff++;
              /* we are done, report error if we receive any more... */
              pp->state = PP_Done;
              return MHD_YES;
            }
          return MHD_NO;
        default:
          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* should never happen! */
        }
    }
  return MHD_YES;
}