*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 xlib/web/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)] } } }.