pike.git
/
src
/
modules
/
_Roxen
/
roxen.c
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/modules/_Roxen/roxen.c:38:
/*! @module _Roxen */ /*! @class HeaderParser *! *! Class for parsing HTTP-requests. */
+
#define FLAG_THROW_ERROR 1
+
#define FLAG_KEEP_CASE 2
+
#define FLAG_NO_FOLD 4
+
#define THP ((struct header_buf *)Pike_fp->current_storage) struct header_buf { unsigned char *headers; unsigned char *pnt; ptrdiff_t hsize, left; int slash_n, tslash_n, spc; int mode; };
pike.git/src/modules/_Roxen/roxen.c:89:
*! @elem string 0 *! Trailing data. *! @elem string 1 *! First line of request. *! @elem mapping(string:string|array(string)) 2 *! Headers. *! @endarray */ { struct pike_string *str = Pike_sp[-args].u.string;
-
int keep_case = 0;
+
struct header_buf *hp = THP;
-
+
int keep_case = hp->mode & FLAG_KEEP_CASE;
+
int fold = !(hp->mode & FLAG_NO_FOLD);
int str_len;
-
int tot_slash_n=hp->
slash
_n, slash_n = hp->
tslash
_n, spc = hp->spc;
+
int tot_slash_n=hp->
tslash
_n, slash_n = hp->
slash
_n, spc = hp->spc;
unsigned char *pp,*ep; struct svalue *tmp; struct mapping *headers; ptrdiff_t os=0, i, j, l; unsigned char *in; if( !( args == 1 || args == 2 ) ) Pike_error("Bad number of arguments to feed().\n"); if( TYPEOF(Pike_sp[-args]) != PIKE_T_STRING ) Pike_error("Wrong type of argument to feed()\n"); if( args == 2 ) {
-
+
/* It doesn't make sense to allow each different feed call to
+
handle case sensitivity differently. Deprecate this when we
+
rewrite the HTTP module. */
if( TYPEOF(Pike_sp[-args+1]) == PIKE_T_INT )
-
keep_case = Pike_sp[-args+1].u.integer
& 1
;
+
keep_case = Pike_sp[-args+1].u.integer;
else Pike_error("Wrong type of argument to feed()\n"); } if( str->size_shift ) Pike_error("Wide string headers not supported\n"); str_len = str->len; while( str_len >= hp->left ) { unsigned char *buf; if( hp->hsize > 512 * 1024 )
pike.git/src/modules/_Roxen/roxen.c:138:
Pike_error("Running out of memory in header parser\n"); } hp->left += 8192; hp->pnt = (hp->headers + hp->hsize - hp->left); } memcpy( hp->pnt, str->str, str_len ); pop_n_elems( args ); /* FIXME: The below does not support lines terminated with just \r. */
-
for( ep=(hp->pnt+str_len),pp=MAXIMUM(hp->headers,hp->pnt
-3
);
+
for( ep=(hp->pnt+str_len),pp=MAXIMUM(hp->headers,hp->pnt);
pp<ep && slash_n<2; pp++ ) if( *pp == ' ' ) { spc++; slash_n = 0; } else if( *pp == '\n' ) { slash_n++; tot_slash_n++; } else if( *pp != '\r' ) { slash_n=0; }
-
hp->slash_n =
tot_
slash_n;
+
hp->slash_n = slash_n;
hp->spc = spc;
-
hp->tslash_n
= slash_n;
+
hp->tslash_n =
tot_
slash_n;
hp->left -= str_len; hp->pnt += str_len; hp->pnt[0] = 0; if( slash_n != 2 ) { /* one newline, but less than 2 space, * --> HTTP/0.9 or broken request */ if( (spc < 2) && tot_slash_n )
pike.git/src/modules/_Roxen/roxen.c:208:
/* Parse headers. */ for(i = 0; i < l; i++) { if(!keep_case && (in[i] > 64 && in[i] < 91)) { in[i]+=32; /* lower_case */ } else if( in[i] == ':' ) {
-
/*
FIXME:
Does not support white space before the colon. */
+
/* Does not support white space before the colon.
This is in
+
line with RFC 7230 product
+
header-field = field-name ":" OWS field-value OWS
*/
/* in[os..i-1] == the header */ int val_cnt = 0; push_string(make_shared_binary_string((char*)in+os,i-os)); /* Skip the colon and initial white space. */ os = i+1; while((in[os]==' ') || (in[os]=='\t')) os++; /* NOTE: We need to support MIME header continuation lines * (Opera uses this...). */ do { for(j=os;j<l;j++) /* Find end of line */ if( in[j] == '\n' || in[j]=='\r') break;
-
+
/* FIXME: Remove header value trailing spaces. */
push_string(make_shared_binary_string((char*)in+os,j-os)); val_cnt++; if((in[j] == '\r') && (in[j+1] == '\n')) j++; os = j+1; i = j; /* Check for continuation line. */
-
} while ((os < l) && ((in[os] == ' ') || (in[os] == '\t')));
+
} while ((os < l) &&
fold &&
((in[os] == ' ') || (in[os] == '\t')));
if (val_cnt > 1) { /* Join partial header values. */ f_add(val_cnt); } if((tmp = low_mapping_lookup(headers, Pike_sp-2))) { if( TYPEOF(*tmp) == PIKE_T_ARRAY ) {
pike.git/src/modules/_Roxen/roxen.c:261:
map_delete(headers, Pike_sp-3); f_aggregate(2); } } mapping_insert(headers, Pike_sp-2, Pike_sp-1); pop_n_elems(2); } else if( in[i]=='\r' || in[i]=='\n' ) {
-
if( THP->mode
==
1
)
+
if( THP->mode
&
FLAG_THROW_ERROR
)
{ /* FIXME: Reset stack so that backtrace shows faulty header. */ Pike_error("Malformed HTTP header.\n"); } else os = i+1; } } push_mapping( headers ); f_aggregate( 3 ); /* data, firstline, headers */ } static void f_hp_create( INT32 args )
-
/*! @decl void create(int throw_errors)
+
/*! @decl void create(
void|
int throw_errors
, void|int keep_case
)
*/ {
-
+
INT_TYPE throw_errors = 0;
+
INT_TYPE keep_case = 0;
+
INT_TYPE no_fold = 0;
+
get_all_args("create",args,".%i%i%i", &throw_errors, &keep_case, &no_fold);
+
if (THP->headers) { free(THP->headers); THP->headers = NULL; } THP->mode = 0;
-
get
_
all
_
args
(
"create",args,".%d",&
THP->mode);
+
if(throw
_
errors) THP->mode |= FLAG
_
THROW_ERROR;
+
if
(
keep_case)
THP->mode
|= FLAG_KEEP_CASE;
+
if(no_fold
)
THP->mode |= FLAG_NO_FOLD
;
THP->headers = xalloc( 8192 ); THP->pnt = THP->headers; THP->hsize = 8192; THP->left = 8192; THP->spc = THP->slash_n = 0; pop_n_elems(args);
-
push_int(0);
+
} /*! @endclass */ static int valid_header_name(struct pike_string *s) { ptrdiff_t i; if (s->size_shift) return 0; for (i = 0; i < s->len; i++) {
pike.git/src/modules/_Roxen/roxen.c:412:
} if (terminator) { *(pnt++) = '\r'; *(pnt++) = '\n'; } pop_n_elems( args ); push_string( end_shared_string( res ) ); }
+
static p_wchar2 parse_hexchar(p_wchar2 hex)
+
{
+
if(hex>='0' && hex<='9')
+
return hex-'0';
+
hex |= 32;
+
return hex-'W';
+
}
+
static void f_http_decode_string(INT32 args) /*! @decl string http_decode_string(string encoded) *! *! Decodes an http transport-encoded string. Knows about @tt{%XX@} and *! @tt{%uXXXX@} syntax. Treats @tt{%UXXXX@} as @tt{%uXXXX@}. It will *! treat '+' as '+' and not ' ', so form decoding needs to replace that *! in a second step. *! *! It also knows about UTF-16 surrogate pairs when decoding @tt{%UXXXX@} *! sequences.
-
*!
-
*! @note
-
*! Performs a best-effort decoding. Invalid and truncated escapes
-
*! will still be decoded.
+
*/ { int proc = 0;
-
int trunc = 0;
+
int size_shift; int got_surrogates = 0; PCHARP foo, end; struct string_builder newstr; if (!args || TYPEOF(Pike_sp[-args]) != PIKE_T_STRING) Pike_error("Invalid argument to http_decode_string(string).\n"); foo = MKPCHARP_STR(Pike_sp[-args].u.string); end = ADD_PCHARP(foo, Pike_sp[-args].u.string->len); size_shift = Pike_sp[-args].u.string->size_shift; /* Count '%' and wide characters. *
-
*
trunc
counts the number of characters that are to be removed.
+
*
proc
counts the number of characters that are to be removed.
*/ for (; COMPARE_PCHARP(foo, <, end);) { p_wchar2 c = EXTRACT_PCHARP(foo); INC_PCHARP(foo, 1); if (c != '%') continue;
-
proc++;
+
/* there are at least 2 more characters */
-
if (SUBTRACT_PCHARP(end, foo) <
2
)
{
-
trunc += SUBTRACT
_
PCHARP
(
end,
foo);
-
break
;
-
}
+
if (SUBTRACT_PCHARP(end, foo) <
=
1
)
+
Pike
_
error
(
"Truncated
http
transport
encoded
string.\n")
;
c = EXTRACT_PCHARP(foo); if (c == 'u' || c == 'U') {
-
if (SUBTRACT_PCHARP(end, foo) <
5
)
{
-
trunc
+=
SUBTRACT
_PCHARP(
end
, foo)
;
-
break;
-
}
+
if (SUBTRACT_PCHARP(end, foo) <
=
4
)
+
Pike_error("Truncated unicode sequence.\n");
+
INC_PCHARP(foo,
1);
+
if (!isxdigit(INDEX
_PCHARP(
foo
,
0)) ||
+
!isxdigit(INDEX_PCHARP(
foo
, 1
)
) ||
+
!isxdigit(INDEX_PCHARP(foo, 2)) ||
+
!isxdigit(INDEX_PCHARP(foo, 3)))
+
Pike_error("Illegal transport encoding.\n");
/* %uXXXX */ if (EXTRACT_PCHARP(foo) != '0' || INDEX_PCHARP(foo, 1) != '0') { if (!size_shift) size_shift = 1; }
-
trunc
+= 5;
-
INC_PCHARP(foo,
5
);
+
proc
+= 5;
+
INC_PCHARP(foo,
4
);
} else {
-
trunc
+= 2;
+
if
(!isxdigit(INDEX_PCHARP(foo, 0)) ||
+
!isxdigit(INDEX_PCHARP(foo, 1)))
+
Pike_error("Illegal transport encoding.\n");
+
proc
+= 2;
INC_PCHARP(foo, 2); } } if (!proc) { pop_n_elems(args-1); return; }
-
init_string_builder_alloc(&newstr, Pike_sp[-args].u.string->len -
trunc
,
+
init_string_builder_alloc(&newstr, Pike_sp[-args].u.string->len -
proc
,
size_shift); foo = MKPCHARP_STR(Pike_sp[-args].u.string); for (; COMPARE_PCHARP(foo, <, end); INC_PCHARP(foo, 1)) {
-
p_wchar2 c =
EXTRACT
_PCHARP(foo);
+
p_wchar2 c =
INDEX
_PCHARP(foo
, 0
);
if (c == '%') { c = INDEX_PCHARP(foo, 1);
-
+
/* The above loop checks that the following sequences
+
* are correct, i.e. that they are not truncated and consist
+
* of hexadecimal chars.
+
*/
if (c == 'u' || c == 'U') {
-
c = 0;
-
if (SUBTRACT_PCHARP(end, foo) > 5) {
+
p_wchar2 hex = INDEX_PCHARP(foo, 2);
-
c = (
((
hex
<'A'
)
?hex:(hex + 9)) & 15)
<<12;
+
c =
parse_hexchar
(hex)<<12;
hex = INDEX_PCHARP(foo, 3);
-
c |= (
((
hex
<'A'
)
?hex:(hex + 9)) & 15)
<<8;
+
c |=
parse_hexchar
(hex)<<8;
hex = INDEX_PCHARP(foo, 4);
-
c |= (
((
hex
<'A'
)
?hex:(hex + 9)) & 15)
<<4;
+
c |=
parse_hexchar
(hex)<<4;
hex = INDEX_PCHARP(foo, 5);
-
c |= (
(
hex
<'A'
)
?hex:(hex + 9)) & 15
;
-
}
+
c |=
parse_hexchar
(hex);
INC_PCHARP(foo, 5); if ((c & 0xf800) == 0xd800) { got_surrogates = 1; } } else {
-
c = 0;
-
if (SUBTRACT_PCHARP(end, foo) > 2) {
+
p_wchar2 hex = INDEX_PCHARP(foo, 1);
-
c = (
((
hex
<'A'
)
?hex:(hex + 9)) & 15)
<<4;
+
c =
parse_hexchar
(hex)<<4;
hex = INDEX_PCHARP(foo, 2);
-
c |= (
(
hex
<'A'
)
?hex:(hex + 9)) & 15
;
-
}
+
c |=
parse_hexchar
(hex);
INC_PCHARP(foo, 2); } } string_builder_putchar(&newstr, c); } pop_n_elems(args); if (got_surrogates) { /* Convert the result string to a byte string. */
pike.git/src/modules/_Roxen/roxen.c:541:
} static void f_html_encode_string( INT32 args ) /*! @decl string html_encode_string(mixed in) *! *! Encodes the @[in] data as an HTML safe string. */ { struct pike_string *str; int newlen;
+
INT32 min;
if( args != 1 ) Pike_error("Wrong number of arguments to html_encode_string\n" ); switch( TYPEOF(Pike_sp[-1]) ) { void o_cast_to_string(); case PIKE_T_INT: case PIKE_T_FLOAT:
pike.git/src/modules/_Roxen/roxen.c:566:
default: o_cast_to_string(); case PIKE_T_STRING: break; } str = Pike_sp[-1].u.string; newlen = str->len;
+
check_string_range(str, 1, &min, NULL);
+
+
if (min > '>') return;
+
#define COUNT(T) { \ T *s = (T *)str->str; \ int i; \ for( i = 0; i<str->len; i++ ) \ switch( s[i] ) \ { \ case 0: /* � */ \ case '<': /* < */ \ case '>': newlen+=3; break;/* > */ \ case '&': /* & */ \
pike.git/src/modules/_Roxen/roxen.c:650:
ADD_FUNCTION("html_encode_string", f_html_encode_string, tFunc(tMix,tStr), 0 ); start_new_program(); ADD_STORAGE( struct header_buf ); set_init_callback( f_hp_init ); set_exit_callback( f_hp_exit ); ADD_FUNCTION("feed", f_hp_feed, tFunc(tStr tOr(tInt01,tVoid),tArr(tOr(tStr,tMapping))), 0);
-
ADD_FUNCTION( "create", f_hp_create, tFunc(tOr(tInt,tVoid),tVoid), ID_PROTECTED );
+
ADD_FUNCTION( "create", f_hp_create, tFunc(tOr(tInt,tVoid)
tOr(tInt
,tVoid)
tOr(tInt
,
tVoid),tVoid),
ID_PROTECTED );
end_class( "HeaderParser", 0 ); } PIKE_MODULE_EXIT { }