/[cwmp]/google/trunk/lib/CWMP/Session.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /google/trunk/lib/CWMP/Session.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 36 by dpavlin, Tue Jun 19 00:38:49 2007 UTC revision 40 by dpavlin, Tue Jun 19 17:29:07 2007 UTC
# Line 4  package CWMP::Server; Line 4  package CWMP::Server;
4  use strict;  use strict;
5  use warnings;  use warnings;
6    
7  use base qw/HTTP::Server::Simple::CGI Class::Accessor/;  use base qw/Class::Accessor/;
8  __PACKAGE__->mk_accessors( qw/  __PACKAGE__->mk_accessors( qw/
9  debug  debug
10    port
11  / );  / );
12    
13    use IO::Socket::INET;
14  use Data::Dump qw/dump/;  use Data::Dump qw/dump/;
15  use CWMP::Request;  use CWMP::Request;
16  use CWMP::Response;  use CWMP::Response;
17  use Carp qw/confess/;  use Carp qw/confess cluck/;
18    
19  =head1 NAME  =head1 NAME
20    
# Line 20  CWMP::Server - implement logic of CWMP p Line 22  CWMP::Server - implement logic of CWMP p
22    
23  =head1 METHODS  =head1 METHODS
24    
25  =head2 handler  =head2 new
26    
27  We override L<HTTP::Server::Simple::CGI/handler> so that we can support    my $server = CWMP::Server->new({ port => 3333 });
28  chunked transfer encoding.  
29    =head2 run
30    
31      $server->run();
32    
33  =cut  =cut
34    
35  sub handler {  sub run {
36      my $self = shift;          my $self = shift;
37    
38      my $chunk;          my $listen = IO::Socket::INET->new(
39                    Listen    => 5,
40    #               LocalAddr => 'localhost',
41                    LocalPort => $self->port,
42                    Proto     => 'tcp',
43                    Blocking  => 1,
44                    ReuseAddr => 1,
45            );
46    
47            warn "waiting for request on port ", $self->port, $/;
48    
49            while ( my $sock = $listen->accept ) {
50                    $sock->autoflush(1);
51    
52                    warn "connection from ", $sock->peerhost, "\n";
53    
54                    $self->process_request( $sock );
55    
56                    warn "...another one bites a dust...\n";
57                    sleep 1;
58            }
59    }
60    
61    sub process_request {
62            my $self = shift;
63    
64            my $sock = shift || die "no sock?";
65    
66            die "not IO::Socket::INET but ", ref( $sock ) unless ( ref($sock) eq 'IO::Socket::INET' );
67    
68            $sock->autoflush( 1 );
69            $sock->blocking( 1 );
70    
71            ### read the first line of response
72            my $line = $sock->getline; # || $self->error(400, "No Data");
73    
74            $line =~ s/[\r\n]+$//;
75            if ($line !~ /^ (\w+) \ + (\S+) \ + (HTTP\/1.\d) $ /x) {
76                    return $self->error(400, "Bad request");
77            }
78            my ($method, $req, $protocol) = ($1, $2, $3);
79            warn "<<<< ",join(" ", time, $method, $req)."\n";
80    
81            ### read in other headers
82            $self->read_headers($sock) || return $self->error(400, "Strange headers");
83    
84            ### do we support the type
85    #       if ($method !~ /GET|POST|HEAD/) {
86            if ($method !~ /POST/) {
87                    return $self->error(400, "Unsupported Method");
88            }
89    
90        my $chunk;
91          my $transfer_encoding = $self->header('Transfer-Encoding');          my $transfer_encoding = $self->header('Transfer-Encoding');
92    
93          if ( $transfer_encoding && $transfer_encoding =~ qr/^chunked/i ) {          if ( $transfer_encoding && $transfer_encoding =~ qr/^chunked/i ) {
94    
95                  my $len = 0;                  my $len = 0;
                 my $hex;  
                 do {  
                         $hex = <STDIN>;         # get chunk length  
                         $hex =~ s/[\n\r]*$//s;  
                         $len = hex( $hex );  
   
                         warn "getting chunk of 0x$hex $len bytes\n" if $self->debug;  
96    
97                          while( $len > 0 ) {                  do {
                                 my $line = <STDIN>;  
                                 $chunk .= $line;  
                                 $len -= length( $line );  
                         }  
98    
99                  } while ( hex( $hex ) != 0 );                          warn "get chunk len\n" if $self->debug;
100          }                          
101                            my $hex;
102                            do {
103                                    $hex = $sock->getline;
104                                    $hex =~ s/[\n\r]+$//;
105                            } until ( $hex ne '' );
106    
107          warn "handler got ", length($chunk), " bytes\n" if $self->debug;                          die "chunk size not valid hex: $hex" unless ( $hex =~ m/^[0-9a-f]+$/i);
108                            $len = hex( $hex );
109    
110      my $cgi  = new CGI( $chunk );                          warn "getting chunk of $len bytes\n" if $self->debug;
111    
112      eval { $self->handle_request($cgi) };                          $sock->read( my $buff, $len );
113      if ($@) {                          $chunk .= $buff;
         my $error = $@;  
         warn $error;  
     }  
 }  
114    
115  =head2 handle_request                          warn "--- $len bytes: --=>||$buff||<=--\n";
116    
117  Implementation of dispatch logic                  } while ( $len > 0 );
118    
119  =cut          } else {
120                    die "right now, we support only Transfer-Encoding: chunked";
121            }
122    
123  sub handle_request {          warn "handler got ", length($chunk), " bytes\n" if $self->debug;
         my ($self, $cgi) = @_;  
                                                                       
         #... do something, print output to default  
         # selected filehandle...  
124    
125          warn "<<< " . localtime() . " " . $ENV{REMOTE_ADDR} . "\n";          warn "<<< " . localtime() . " " . $sock->peerhost . "\n";
126    
127          warn "not SOAP request" unless defined ( $cgi->header('SOAPAction') );          die "not SOAP request" unless defined ( $self->header('SOAPAction') );
128    
129          my $state;          my $state;
130    
131          if ( my $payload = $cgi->param('POSTDATA') ) {          if ( $chunk ) {
132                  warn "request payload:\n$payload\n" if $self->debug;                  warn "## request chunk: ",length($chunk)," bytes\n$chunk\n" if $self->debug;
133    
134                  $state = CWMP::Request->parse( $payload );                  $state = CWMP::Request->parse( $chunk );
135    
136                  warn "acquired state = ", dump( $state );                  warn "acquired state = ", dump( $state ), "\n";
137                    
138          } else {          } else {
139                  warn "empty request\n";                  warn "empty request\n";
140          }          }
141    
142    
143          my $response = CWMP::Response->new({ debug => $self->debug });          my $response = CWMP::Response->new({ debug => $self->debug });
144    
145          print "Content-Type: text/xml\r\n\r\n";          print $self->status(200), $self->content_type('text/xml; charset="utf-8"'), "\r\n";
146    
147            print "Server: AcmeCWMP/42\r\nSOAPServer: AcmeCWMP/42\r\n";
148    
149            print "Set-Cookie: ID=" , $state->{ID}, "; path=/\r\n" if ( $state->{ID} );
150            
151            my $xml = '';
152    
153          if ( my $dispatch = $state->{_dispatch} ) {          if ( my $dispatch = $state->{_dispatch} ) {
154                  if ( $response->can( $dispatch ) ) {                  if ( $response->can( $dispatch ) ) {
155                          warn ">>> dispatching to $dispatch\n";                          warn ">>> dispatching to $dispatch\n";
156                          print $response->$dispatch;                          $xml = $response->$dispatch( $state ) . "\r\n";
157                            warn "## response payload: ",length($xml)," bytes\n$xml\n";
158                  } else {                  } else {
159                          confess "can't dispatch to $dispatch";                          confess "can't dispatch to $dispatch";
160                  }                  }
161          } else {          } else {
162                  warn ">>> empty response\n";                  warn ">>> empty response\n";
163          }          }
164            
165            print "Content-length: ", length( $xml ), "\r\n\r\n";
166            print $xml or die "can't send response";
167    
168            warn "### request over";
169    
170  };  };
171    
 1;  
172    
173    sub read_headers {
174      my $self = shift;
175    
176            my $sock = shift || die "no sock?";
177    
178      $self->{headers} = {};
179    
180      while (defined($_ = $sock->getline)) {
181        s/[\r\n]+$//;
182        last unless length $_;
183            warn "-- $_\n";
184        return 0 if ! /^ ([\w\-]+) :[\ \t]* (.*) $/x;
185        $self->{headers}->{$1} = $2;
186      }
187    
188      return 1;
189    }
190    
191    sub header {
192            my $self = shift;
193            my $header = shift || die "no header?";
194            if ( defined( $self->{headers}->{$header} )) {
195                    return $self->{headers}->{$header};
196            } else {
197                    return;
198            }
199    }
200    
201    sub content_type {
202      my ($self, $type) = @_;
203      $self->http_header;
204      return "Content-type: $type\r\n";
205    }
206    
207    sub error{
208      my ($self, $number, $msg) = @_;
209      print $self->status($number, $msg), "\r\n";
210      warn "Error - $number - $msg\n";
211    }
212    
213    sub status {
214      my ($self, $number, $msg) = @_;
215      $msg = '' if ! defined $msg;
216      return if $self->http_header($number);
217      return "Status $number: $msg\r\n";
218    }
219    
220    sub http_header {
221      my $self = shift;
222      my $number = shift || 200;
223      return if ! delete $self->{needs_header};
224      print "HTTP/1.0 $number\r\n";
225      return 1;
226    }
227    
228    1;

Legend:
Removed from v.36  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26