our
$MAX_MESSAGE_SIZE
= 10 * 2048;
sub
new {
my
$class
=
shift
;
$class
=
ref
$class
if
ref
$class
;
my
$self
= {
@_
};
bless
$self
,
$class
;
$self
->{version} ||=
''
;
$self
->{buffer} =
''
;
$self
->{fields} ||= {};
$self
->{max_message_size} ||=
$MAX_MESSAGE_SIZE
;
$self
->{cookies} ||= [];
$self
->state(
'first_line'
);
return
$self
;
}
sub
secure {
@_
> 1 ?
$_
[0]->{secure} =
$_
[1] :
$_
[0]->{secure} }
sub
fields {
shift
->{fields} }
sub
field {
my
$self
=
shift
;
my
$name
=
lc
shift
;
return
$self
->fields->{
$name
}
unless
@_
;
$self
->fields->{
$name
} =
$_
[0];
return
$self
;
}
sub
error {
my
$self
=
shift
;
return
$self
->{error}
unless
@_
;
my
$error
=
shift
;
$self
->{error} =
$error
;
$self
->state(
'error'
);
return
$self
;
}
sub
subprotocol {
@_
> 1 ?
$_
[0]->{subprotocol} =
$_
[1] :
$_
[0]->{subprotocol};
}
sub
host {
@_
> 1 ?
$_
[0]->{host} =
$_
[1] :
$_
[0]->{host} }
sub
origin {
@_
> 1 ?
$_
[0]->{origin} =
$_
[1] :
$_
[0]->{origin} }
sub
version {
@_
> 1 ?
$_
[0]->{version} =
$_
[1] :
$_
[0]->{version} }
sub
number1 {
@_
> 1 ?
$_
[0]->{number1} =
$_
[1] :
$_
[0]->{number1} }
sub
number2 {
@_
> 1 ?
$_
[0]->{number2} =
$_
[1] :
$_
[0]->{number2} }
sub
challenge {
@_
> 1 ?
$_
[0]->{challenge} =
$_
[1] :
$_
[0]->{challenge} }
sub
checksum {
my
$self
=
shift
;
if
(
@_
) {
$self
->{checksum} =
$_
[0];
return
$self
;
}
return
$self
->{checksum}
if
defined
$self
->{checksum};
Carp::croak(
qq/number1 is required/
)
unless
defined
$self
->number1;
Carp::croak(
qq/number2 is required/
)
unless
defined
$self
->number2;
Carp::croak(
qq/challenge is required/
)
unless
defined
$self
->challenge;
my
$checksum
=
''
;
$checksum
.=
pack
'N'
=>
$self
->number1;
$checksum
.=
pack
'N'
=>
$self
->number2;
$checksum
.=
$self
->challenge;
$checksum
= Digest::MD5::md5(
$checksum
);
return
$self
->{checksum} ||=
$checksum
;
}
sub
parse {
my
$self
=
shift
;
return
1
unless
defined
$_
[0];
return
if
$self
->error;
return
unless
$self
->_append(
@_
);
while
(!
$self
->is_state(
'body'
) &&
defined
(
my
$line
=
$self
->_get_line)) {
if
(
$self
->state eq
'first_line'
) {
return
unless
defined
$self
->_parse_first_line(
$line
);
$self
->state(
'fields'
);
}
elsif
(
$line
ne
''
) {
return
unless
defined
$self
->_parse_field(
$line
);
}
else
{
$self
->state(
'body'
);
last
;
}
}
return
1
unless
$self
->is_state(
'body'
);
my
$rv
=
$self
->_parse_body;
return
unless
defined
$rv
;
return
$rv
unless
ref
$rv
;
$_
[0] =
$self
->{buffer}
unless
readonly
$_
[0] ||
ref
$_
[0];
return
$self
->done;
}
sub
_extract_number {
my
$self
=
shift
;
my
$key
=
shift
;
my
$number
=
join
''
=>
$key
=~ m/\d+/g;
my
$spaces
=
$key
=~ s/ / /g;
return
if
$spaces
== 0;
return
int
(
$number
/
$spaces
);
}
sub
_append {
my
$self
=
shift
;
return
if
$self
->error;
if
(
ref
$_
[0]) {
$_
[0]->
read
(
my
$buf
,
$self
->{max_message_size});
$self
->{buffer} .=
$buf
;
}
else
{
$self
->{buffer} .=
$_
[0];
$_
[0] =
''
unless
readonly
$_
[0];
}
if
(
length
$self
->{buffer} >
$self
->{max_message_size}) {
$self
->error(
'Message is too long'
);
return
;
}
return
$self
;
}
sub
_get_line {
my
$self
=
shift
;
if
(
$self
->{buffer} =~ s/^(.*?)\x0d?\x0a//) {
return
$1;
}
return
;
}
sub
_parse_first_line {
shift
}
sub
_parse_field {
my
$self
=
shift
;
my
$line
=
shift
;
my
(
$name
,
$value
) =
split
/:\s*/ =>
$line
=> 2;
unless
(
defined
$name
&&
defined
$value
) {
$self
->error(
'Invalid field'
);
return
;
}
$self
->field(
$name
=>
$value
);
if
(
$name
=~ m/^x-forwarded-proto$/i) {
$self
->secure(1);
}
return
$self
;
}
sub
_parse_body {
shift
}
1;