view release on metacpan or search on metacpan
http_parser.c
http_parser.h
lib/HTTP/Parser2/XS.pm
Makefile.PL
MANIFEST This list of files
parser2.h
ppport.h
README
t/00-use.t
t/01-simple.t
t/02-request-keepalive.t
t/03-request-rv.t
t/04-response-rv.t
t/05-response-keepalive.t
TODO
XS.xs
META.yml Module meta-data (added by MakeMaker)
$r->{'_uri'}
Decoded request uri without query string. A lot like $uri in
nginx.
$r->{'_query_string'}
Query string. Everything after question mark.
$r->{'_protocol'}
Protocol and version. Either "HTTP/1.0" or "HTTP/1.1".
$r->{'_keepalive'}
Either 1 or 0. Examines connection header and protocol version
to decide whether or not keep-alive connection is desired. And
if it is sets "$r->{'_keepalive'}" to 1.
$r->{'_content_length'}
Parses content-length header. Stores length as a numeric value
(SvNV to be precise) or undef if there is no content-length
header.
$rv = parse_http_response($buf, $r)
Parses HTTP response in $buf into the hashref $r. Returns length of
the header on success, -1 on error and -2 if response isn't complete
yet, i.e. doesn't have an entire header. Converts each header name
$r->{'_protocol'}
Protocol and version. Either "HTTP/1.0" or "HTTP/1.1".
$r->{'_status'}
Response status. For example "200" for "HTTP/1.0 200 OK"
response.
$r->{'_message'}
Status message. For example "OK" for "HTTP/1.0 200 OK" response.
$r->{'_keepalive'}
Either 1 or 0. Examines connection header and protocol version
to decide whether or not keep-alive connection is desired. And
if it is sets "$r->{'_keepalive'}" to 1.
$r->{'_content_length'}
Parses content-length header. Stores length as a numeric value
(SvNV to be precise) or undef if there is no content-length
header.
SEE ALSO
HTTP::Parser::XS
AUTHOR
- HTTP tests
- ditch HTTP::Parser::XS code and use nginx-like parser
instead;
- make _keepalive flag more sophisticated, i.e. disable keepalive
on POSTs for buggy user agents, like nginx does;
eg/example1.pl view on Meta::CPAN
#!/usr/bin/perl
use strict;
use warnings;
use HTTP::Parser2::XS;
{
my $buf = "GET /a%20s?foo=bar HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
my $rv = parse_http_request($buf, $r);
if ($rv == -1) {
# bad request or internal error
} elsif ($rv == -2) {
# incomplete request, call again when there is more data
# in the buffer
eg/example1.pl view on Meta::CPAN
print << " END";
rv = $rv
method = "$r->{'_method'}"
request_uri = "$r->{'_request_uri'}"
uri = "$r->{'_uri'}"
query_string = "$r->{'_query_string'}"
protocol = "$r->{'_protocol'}"
keepalive = $r->{'_keepalive'}
END
}
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"Content-Type: text/html\x0d\x0a".
eg/example1.pl view on Meta::CPAN
# $rv contains the length of the request header on success
print << " END";
rv = $rv
protocol = "$r->{'_protocol'}"
status = "$r->{'_status'}"
message = "$r->{'_message'}"
keepalive = $r->{'_keepalive'}
END
}
};
http_parser.c view on Meta::CPAN
STRLEN buf_len;
const char* method;
size_t method_len;
const char* path;
size_t path_len;
int minor_version;
struct phr_header headers[MAX_HEADERS];
size_t num_headers, question_at;
size_t i;
int ret;
int keepalive = 0;
HV* env;
SV* last_value;
char *content_length_str = NULL;
size_t content_length_strlen = 0;
char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") - 1];
buf_str = SvPV(buf, buf_len);
num_headers = MAX_HEADERS;
ret = phr_parse_request(buf_str, buf_len, &method, &method_len, &path,
&path_len, &minor_version, headers, &num_headers, 0);
http_parser.c view on Meta::CPAN
if (question_at != path_len)
++question_at;
hv_store(env, "_query_string", sizeof("_query_string") - 1,
newSVpvn(path + question_at, path_len - question_at), 0);
sprintf(tmp, "HTTP/1.%d", minor_version);
hv_store(env, "_protocol", sizeof("_protocol") - 1,
newSVpv(tmp, 0), 0);
if (minor_version == 1) {
keepalive = 1;
}
last_value = NULL;
for (i = 0; i < num_headers; ++i) {
if (headers[i].name != NULL) {
const char* name;
size_t name_len;
SV** slot;
AV *av; /* for arrayref */
http_parser.c view on Meta::CPAN
}
for (s = headers[i].name, n = headers[i].name_len, d = tmp;
n != 0;
s++, --n, d++)
*d = tol(*s);
name = tmp;
name_len = headers[i].name_len;
if (str_eq(name, name_len, "connection", sizeof("connection") - 1)) {
if (str_lc_eq(headers[i].value,
headers[i].value_len > (sizeof("keep-alive") - 1)
? (sizeof("keep-alive") - 1)
: headers[i].value_len,
"keep-alive", sizeof("keep-alive") - 1)) {
keepalive = 1;
} else {
keepalive = 0;
}
}
if (str_eq(name, name_len, "content-length",
sizeof("content-length") - 1)) {
content_length_str = (char *) headers[i].value;
content_length_strlen = headers[i].value_len;
}
}
slot = hv_fetch(env, name, name_len, 1);
http_parser.c view on Meta::CPAN
}
last_value = sv;
} else {
/* continuing lines of a mulitiline header */
sv_catpvn(last_value, headers[i].value, headers[i].value_len);
}
}
if (ret > 0) {
hv_store(env, "_keepalive", sizeof("_keepalive") - 1,
newSViv(keepalive), 0);
hv_store(env, "_content_length", sizeof("_content_length") - 1,
str_svnv(content_length_str, content_length_strlen), 0);
}
failed:
return ret;
}
http_parser.c view on Meta::CPAN
const char* msg;
size_t msg_len;
struct phr_header headers[MAX_HEADERS];
size_t num_headers = MAX_HEADERS;
STRLEN buf_len;
const char *buf_str;
size_t last_len = 0;
size_t i;
char name[MAX_HEADER_NAME_LEN]; /* temp buffer for normalized names */
int ret;
int keepalive = 0;
HV* env;
SV* last_value;
char *content_length_str = NULL;
size_t content_length_strlen = 0;
char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") - 1];
buf_str = SvPV(buf, buf_len);
num_headers = MAX_HEADERS;
ret = phr_parse_response(buf_str, buf_len, &minor_version, &status, &msg,
http_parser.c view on Meta::CPAN
sprintf(tmp, "HTTP/1.%d", minor_version);
hv_store(env, "_protocol", sizeof("_protocol") - 1,
newSVpv(tmp, 0), 0);
sprintf(tmp, "%d", status);
hv_store(env, "_status", sizeof("_status") - 1,
newSVpv(tmp, 0), 0);
if (minor_version == 1) {
keepalive = 1;
}
last_value = NULL;
for (i = 0; i < num_headers; ++i) {
if (headers[i].name != NULL) {
const char* name;
size_t name_len;
SV** slot;
AV *av; /* for arrayref */
http_parser.c view on Meta::CPAN
}
for (s = headers[i].name, n = headers[i].name_len, d = tmp;
n != 0;
s++, --n, d++)
*d = tol(*s);
name = tmp;
name_len = headers[i].name_len;
if (str_eq(name, name_len, "connection", sizeof("connection") - 1)) {
if (str_lc_eq(headers[i].value,
headers[i].value_len > (sizeof("keep-alive") - 1)
? (sizeof("keep-alive") - 1)
: headers[i].value_len,
"keep-alive", sizeof("keep-alive") - 1)) {
keepalive = 1;
} else {
keepalive = 0;
}
}
if (str_eq(name, name_len, "content-length",
sizeof("content-length") - 1)) {
content_length_str = (char *) headers[i].value;
content_length_strlen = headers[i].value_len;
}
}
http_parser.c view on Meta::CPAN
}
last_value = sv;
} else {
/* continuing lines of a mulitiline header */
sv_catpvn(last_value, headers[i].value, headers[i].value_len);
}
}
if (ret > 0) {
hv_store(env, "_keepalive", sizeof("_keepalive") - 1,
newSViv(keepalive), 0);
hv_store(env, "_content_length", sizeof("_content_length") - 1,
str_svnv(content_length_str, content_length_strlen), 0);
}
done:
return ret;
}
lib/HTTP/Parser2/XS.pm view on Meta::CPAN
Decoded request uri without query string. A lot like C<$uri> in nginx.
=item $r->{'_query_string'}
Query string. Everything after question mark.
=item $r->{'_protocol'}
Protocol and version. Either "HTTP/1.0" or "HTTP/1.1".
=item $r->{'_keepalive'}
Either C<1> or C<0>. Examines connection header and protocol version to
decide whether or not keep-alive connection is desired. And if it is
sets C<< $r->{'_keepalive'} >> to C<1>.
=item $r->{'_content_length'}
Parses content-length header. Stores length as a numeric value
(SvNV to be precise) or undef if there is no content-length header.
=back
=item $rv = parse_http_response($buf, $r)
lib/HTTP/Parser2/XS.pm view on Meta::CPAN
Protocol and version. Either "HTTP/1.0" or "HTTP/1.1".
=item $r->{'_status'}
Response status. For example "200" for "HTTP/1.0 200 OK" response.
=item $r->{'_message'}
Status message. For example "OK" for "HTTP/1.0 200 OK" response.
=item $r->{'_keepalive'}
Either C<1> or C<0>. Examines connection header and protocol version to
decide whether or not keep-alive connection is desired. And if it is
sets C<< $r->{'_keepalive'} >> to C<1>.
=item $r->{'_content_length'}
Parses content-length header. Stores length as a numeric value
(SvNV to be precise) or undef if there is no content-length header.
=back
=back
t/01-simple.t view on Meta::CPAN
use Test::More tests => 9;
BEGIN {
use_ok('HTTP::Parser2::XS')
};
{
my $buf = "GET /a%20s HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"Content-Length: 16000000000\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok exists $r->{'host'}, "host header exists";
ok $r->{'host'}->[0] eq 'localhost', "correct host";
ok $r->{'_uri'} eq '/a s', "correct _uri (url_decoded)";
ok exists $r->{'content-length'}, "has content length header";
ok $r->{'_content_length'}, "has _content_length";
t/02-request-keepalive.t view on Meta::CPAN
use Test::More tests => 6;
BEGIN {
use_ok('HTTP::Parser2::XS')
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (connection: keep-alive)";
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: Keep-Alive, asdf\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (connection: Keep-Alive, asdf)";
};
{
my $buf = "GET / HTTP/1.1\x0d\x0a".
"Host: localhost\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (HTTP/1.1)";
};
{
my $buf = "GET / HTTP/1.1\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: close, qwerrrr\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok $r->{'_keepalive'} == 0, "keepalive (HTTP/1.1, connection: close)";
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: close, asfdasdf\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_request($buf, $r);
ok $r->{'_keepalive'} == 0, "keepalive (HTTP/1.0, connection: close)";
};
t/03-request-rv.t view on Meta::CPAN
use Test::More tests => 5;
BEGIN {
use_ok('HTTP::Parser2::XS')
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
my $rv = parse_http_request($buf, $r);
ok $rv > 0, "rv > 0, complete request";
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: local";
t/03-request-rv.t view on Meta::CPAN
"\x0d\x0a";
my $r = {};
my $rv = parse_http_request($buf, $r);
ok $rv == -1, "rv == -1, bad request" or diag "rv = $rv";
};
{
my $buf = "GET / HTTP/1.0\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection".("x" x 1024).": keep-alive\x0d\x0a".
"\x0d\x0a"; my $r = {};
my $rv = parse_http_request($buf, $r);
ok $rv == -1, "rv == -1, too long header" or diag "rv = $rv";
};
t/04-response-rv.t view on Meta::CPAN
use warnings;
use Test::More tests => 5;
BEGIN {
use_ok('HTTP::Parser2::XS')
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
my $rv = parse_http_response($buf, $r);
ok $rv > 0, "rv > 0, complete response";
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Host: local";
t/04-response-rv.t view on Meta::CPAN
my $buf = "BOOMBOOMZCZXXZXCCZX\x0d\x0a".
"\x0d\x0a";
my $r = {};
my $rv = parse_http_response($buf, $r);
ok $rv == -1, "rv == -1, bad response" or diag "rv = $rv";
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Connection".("x" x 1024).": keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
my $rv = parse_http_response($buf, $r);
ok $rv == -1, "rv == -1, too long header" or diag "rv = $rv";
};
t/05-response-keepalive.t view on Meta::CPAN
use Test::More tests => 6;
BEGIN {
use_ok('HTTP::Parser2::XS')
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: keep-alive\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_response($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (connection: keep-alive)";
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: Keep-Alive, asdf\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_response($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (connection: Keep-Alive, asdf)";
};
{
my $buf = "HTTP/1.1 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_response($buf, $r);
ok $r->{'_keepalive'} == 1, "keepalive (HTTP/1.1)";
};
{
my $buf = "HTTP/1.1 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: close, qwerrrr\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_response($buf, $r);
ok $r->{'_keepalive'} == 0, "keepalive (HTTP/1.1, connection: close)";
};
{
my $buf = "HTTP/1.0 200 OK\x0d\x0a".
"Host: localhost\x0d\x0a".
"Connection: close, asfdasdf\x0d\x0a".
"\x0d\x0a";
my $r = {};
parse_http_response($buf, $r);
ok $r->{'_keepalive'} == 0, "keepalive (HTTP/1.0, connection: close)";
};