CXM_http_get_common.anubis 6.91 KB

 *Project*                             The Anubis Project
   
 *Title*                       Getting a document from the Web.
   
 *Copyright*                     Copyright (c) Alain Prouté 2001. 


 *Author*       Alain Prouté

   
   
   This  file  contains  the types  and  functions  which  are  common to  'http_get'  and
   'https_get'.
   
read tools/basis.anubis   
read tools/findstring.anubis  
read system/string.anubis   
read CXM_common.anubis   
 read web/html.anubis   


   
   Body of HTTP requests may also contain name-value pairs. We call them HTTP arguments:
   
public type HTTP_argument:
  http_argument(String name, String value). 
   

   
   We begin by several simple tools. 

   'crlf' and 'crlfcrlf' are defined in 'basis.anubis'. 
   
public define Maybe(Int)
  has_double_crlf
    (
      String s,
    ) =
  find(crlfcrlf,s,0). 
   
   
   
   
   Formatting a list of HTTP arguments. 
   
public define String
  format_http_args
    (
      List(HTTP_argument) l
    ) =
  if l is 
    {
      [ ]          then "",
      [h . t]      then 
        if t is 
          {
            [ ]     then if h is http_argument(n,v) then n + "=" + v,
            [_ . _]   then if h is http_argument(n,v) then n + "=" + v + "&" + format_http_args(t)
          }
    }.
   

   
   Formatting the headers. 
   
public define String 
  format_headers
    (
      List(HTTP_header) headers
    ) = 
  if headers is 
    {
      [ ] then "", 
      [h . t] then if h is http_header(n,v) then 
        n + ": " + v + crlf + format_headers(t)
    }.
   
   
   
   
   
//public define String 
//  format
//    (
//      DNS_Result r
//    ) =
//  if r is 
//    {
//      host_not_found          then "host not found",
//      no_address_found        then "no address found for this host",
//      try_again               then "DNS server is busy, try again later",
//      non_recoverable_error   then "non recoverable DNS error",
//      ok(n)                   then should_not_happen("ok")  // should never happen
//    }.
   
   
public define String 
  format
    (
      NetworkConnectError e
    ) =
  if e is 
    {
      cannot_create_the_socket         then "cannot create the socket",
      address_port_not_available       then "address:port not available",
      connection_refused               then "connection refused",
      network_unreachable              then "network is unreachable",
      address_port_already_in_use      then "address:port already in use",
      out_of_time                      then "out of time"
    }.

public define String 
  format
    (
      SSLConnectError e
    ) =
  if e is 
    {
      tcp_error(nce)                     then format(nce), 
      cannot_create_SSL_object           then "cannot create SSL object",
      cannot_connect_under_SSL           then "cannot connect under SSL", 
      cannot_trust_server_certificate    then "cannot trust server certificate"
    }.

   
   
   The next function empties the standard input (the keybord normally). 
   
define One
  empty_stdin
    (
      One dummy
    ) =
  if *stdin is 
    {
      failure then unique, 
      success(c) then 
        if c = 10
        then unique
        else empty_stdin(dummy)
    }. 
   
   
   The next function returns true if the user answers Y or y. 
   
public define Bool
  yes
    =
  if *stdin is 
    {
      failure then should_not_happen(false),   // this can never happen, because stdin is never closed
      success(c) then 
        empty_stdin(unique); 
        (c = 'Y' | c = 'y')
    }. 

   
   
   Separating the server name from the port. 
   
public define (String,Word32)
   separate_name_port
     (
       String server_name,
       Word32 default_port
     ) =
   if find(":",server_name,0) is 
     {
       failure then (server_name,default_port),
       success(n) then 
         (substr(server_name,0,n),
          if decimal_scan(substr(server_name,n+1,length(server_name)-n-1)) is 
            {
              failure then default_port,
              success(p) then truncate_to_Word32(p)
            })
     }.
   
   
   
   
   
   Separating the headers.  The  headers are comming in the form of  a unique string. They
   should be put in the form of a list of pairs of strings (one list element per header).
   
   We do  that in  two steps. (1)  separate the headers  into a  list of strings  (one per
   header), and (2) separate each string into a pair of strings (name,value). 

   
define HTTP_header
  separate_header
    (
      String header,
      Int i
    ) =
  if nth(i,header) is 
    {
      failure then http_header(header,""), 
      success(c) then 
        if c = ':'          // separator
        then http_header(substr(header,0,i),substr(header,i+1,length(header)-i-1))
        else separate_header(header,i+1)
    }.
  

   Headers are separated from each other by CRLF not followed by a blank character. 
   
define List(HTTP_header)
  separate_headers
    (
      String headers,
      Int start, 
    ) =
  if find("\r\n",headers,start) is 
    {
      failure then [separate_header(substr(headers,start,length(headers)-start),0)], 
      success(end) then
        [separate_header(substr(headers,start,end-start),0) . separate_headers(headers,end+2)]
    }. 

public define List(HTTP_header)
  separate_headers
    (
      String headers,
    ) =
  separate_headers(headers,0). 
   
   
public define One
  print_headers
    (
      List(HTTP_header) headers
    ) =
  if headers is 
    {
      [ ] then unique, 
      [h . t] then 
        if h is http_header(l,r) then 
          print("  "); print(l); print(": "); print(r); print("\n"); print_headers(t)
    }.
   
   
//public define Word8
//  force_nth
//    (
//      Int n, 
//      String s
//    ) =
//  if nth(n,s) is 
//    {
//      failure then 0, 
//      success(c) then c
//    }.
   
   
public define List(HTTP_header)
  get_headers
    (
      List(String) args
    ) =
  if args is
    {
      [ ] then [ ],
      [h . t] then if nth(0,h) is 
        {
          failure then should_not_happen([]), 
          success(c) then if c = '=' 
          then if t is
            {
              [ ] then [http_header(substr(h,1,length(h)-1),"")],
              [u . v] then [http_header(substr(h,1,length(h)-1),u) . get_headers(v)]
            }
          else get_headers(t)
        }
    }.

public define List(HTTP_argument)
  get_arguments
    (
      List(String) args
    ) =
  if args is
    {
      [ ] then [ ],
      [h . t] then if nth(0,h) is 
        {
          failure then should_not_happen([]), 
          success(c) then if c = '=' 
            then if t is 
                   { 
                     [ ] then [ ], 
                     [u . v] then get_arguments(v) 
                   }
            else if c = '-'
              then get_arguments(t) 
              else if t is 
                {
                  [ ] then [http_argument(h,"")], 
                  [u . v] then [http_argument(h,u) . get_arguments(v)]
                }
        }
     }.