apreq_parser_multipart.c revision 6ac28b74a504006c016d4df3fb84d2cd2e373942
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_parser.h"
#include "apreq_error.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_strmatch.h"
#ifndef CRLF
#define CRLF "\015\012"
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define PARSER_STATUS_CHECK(PREFIX) do { \
return APREQ_ERROR_GENERAL; \
return APR_SUCCESS; \
return APR_INCOMPLETE; \
} while (0);
/* maximum recursion level in the mfd parser */
#define MAX_LEVEL 8
struct mfd_ctx {
const apr_strmatch_pattern *pattern;
char *bdry;
enum {
} status;
const char *param_name;
unsigned level;
};
const char *start_string)
{
apr_bucket *e;
e = APR_BUCKET_NEXT(e))
{
const char *buf;
if (slen == 0)
return APR_SUCCESS;
if (APR_BUCKET_IS_EOS(e))
return APR_EOF;
if (s != APR_SUCCESS)
return s;
if (blen == 0)
continue;
return APREQ_ERROR_GENERAL;
slen -= bytes_to_check;
}
/* slen > 0, so brigade isn't large enough yet */
return APR_INCOMPLETE;
}
const apr_strmatch_pattern *pattern,
const char *bdry)
{
while ( e != APR_BRIGADE_SENTINEL(in) ) {
const char *buf;
apr_status_t s;
if (APR_BUCKET_IS_EOS(e))
return APR_EOF;
if (s != APR_SUCCESS)
return s;
if (len == 0) {
apr_bucket *f = e;
e = APR_BUCKET_NEXT(e);
continue;
}
/* complete match */
e = APR_BUCKET_NEXT(e);
do {
} while (APR_BRIGADE_FIRST(in) != e);
return APR_SUCCESS;
}
/* partial match */
e = APR_BUCKET_NEXT(e);
continue;
}
else if (off > 0) {
/* prior (partial) strncmp failed,
* so we can move previous buckets across
* and retest buf against the full bdry.
*/
/* give hints to GCC by making the brigade volatile, otherwise the
* loop below will end up being endless. See:
*/
do {
} while (e != APR_BRIGADE_FIRST(in_v));
off = 0;
}
else {
if (idx >= 0)
}
}
else
/* Theoretically idx should never be 0 here, because we
* already tested the front of the brigade for a potential match.
* However, it doesn't hurt to allow for the possibility,
* since this will just start the whole loop over again.
*/
if (idx >= 0)
apr_bucket_split(e, idx);
e = APR_BRIGADE_FIRST(in);
}
return APR_INCOMPLETE;
}
static
const char *temp_dir,
unsigned level)
{
apr_status_t s;
return NULL; /* missing semicolon */
*ct++ = 0;
if (s != APR_SUCCESS)
return NULL; /* missing boundary */
return ctx;
}
{
apr_status_t s;
return APREQ_ERROR_GENERAL;
}
case MFD_INIT:
{
if (s != APR_SUCCESS) {
return s;
}
/* Be polite and return any preamble text to the caller. */
}
/* fall through */
case MFD_NEXTLINE:
{
if (s == APR_EOF) {
return APR_SUCCESS;
}
if (s != APR_SUCCESS) {
return s;
}
char *line;
return APR_SUCCESS;
}
}
}
/* fall through */
case MFD_HEADER:
{
/* flush out header parser internal structs for reuse */
}
switch (s) {
case APR_SUCCESS:
break;
case APR_INCOMPLETE:
return APR_INCOMPLETE;
default:
return s;
}
}
/* fall through */
case MFD_POST_HEADER:
{
/* Must handle special case of missing CRLF (mainly
* coming from empty file uploads). See RFC2065 S5.1.1:
*
* body-part = MIME-part-header [CRLF *OCTET]
*
* So the CRLF we already matched in MFD_HEADER may have been
* part of the boundary string! Both Konqueror (v??) and
* Mozilla-0.97 are known to emit such blocks.
*
* Here we first check for this condition with
* brigade_start_string, and prefix the brigade with
* an additional CRLF bucket if necessary.
*/
apr_bucket *e;
case APR_INCOMPLETE:
return APR_INCOMPLETE;
case APR_SUCCESS:
/* part has no body- return CRLF to front */
break;
default:
; /* has body, ok */
}
/* First check to see if must descend into a new multipart
* block. If we do, create a new parser and pass control
* to it.
*/
goto mfd_parse_brigade;
}
if (s == APR_SUCCESS) {
}
else {
"Content-ID");
}
}
next_ctx);
goto mfd_parse_brigade;
}
/* Look for a normal form-data part. */
if (s != APR_SUCCESS) {
goto mfd_parse_brigade;
}
if (s == APR_SUCCESS) {
goto mfd_parse_brigade;
}
else {
/* fall thru */
}
}
/* else check for a file part in a multipart section */
goto mfd_parse_brigade;
}
goto mfd_parse_brigade;
}
else {
}
else {
name = "";
nlen = 0;
}
filename = "";
flen = 0;
goto mfd_parse_brigade;
}
}
/* fall through */
case MFD_PARAM:
{
apreq_value_t *v;
switch (s) {
case APR_INCOMPLETE:
return s;
case APR_SUCCESS:
if (s != APR_SUCCESS) {
return s;
}
*(const apreq_value_t **)&v = ¶m->v;
if (s != APR_SUCCESS) {
return s;
}
}
apreq_value_table_add(v, t);
goto mfd_parse_brigade;
default:
return s;
}
}
break; /* not reached */
case MFD_UPLOAD:
{
switch (s) {
case APR_INCOMPLETE:
if (s != APR_SUCCESS) {
return s;
}
}
return (s == APR_SUCCESS) ? APR_INCOMPLETE : s;
case APR_SUCCESS:
if (s != APR_SUCCESS) {
return s;
}
}
apreq_value_table_add(¶m->v, t);
if (s != APR_SUCCESS)
return s;
goto mfd_parse_brigade;
default:
return s;
}
}
break; /* not reached */
case MFD_MIXED:
{
switch (s) {
case APR_SUCCESS:
goto mfd_parse_brigade;
case APR_INCOMPLETE:
return APR_INCOMPLETE;
default:
return s;
}
}
break; /* not reached */
default:
return APREQ_ERROR_GENERAL;
}
return APR_INCOMPLETE;
}