Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

HTTP

std/http fetches web pages and talks to web APIs. http.Fetch( url ) sends a GET and returns the whole reply as a Response: the status, the headers and the body. https URLs work the same way, encrypted by std/tls.

#cmdline "-mt"
#import "std/http"
#import "std/net"
#import "std/fs"

'' A web server that answers one request, on this machine, so the example
'' needs no network. It reads the request up to the blank line, then replies.
sub Serve( byval p as any ptr )
    dim as net.TcpListener ptr lis = p
    dim c as net.TcpStream
    if lis->Accept( c, 5000 ).IsOk( ) = false then exit sub
    dim as string seen
    dim as ubyte b( 0 to 1023 )
    while instr( seen, !"\r\n\r\n" ) = 0
        dim got as fs.FsResultI64 = c.Read( @b( 0 ), 1024 )
        if got.IsOk( ) = false orelse got.Value( ) = 0 then exit while
        for i as long = 0 to got.Value( ) - 1
            seen &= chr( b( i ) )
        next
    wend
    c.WriteUtf8( !"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n" & _
                 !"Content-Length: 13\r\n\r\nhello, client" )
    c.Close( )
end sub

sub Main( )
    dim lis as net.TcpListener
    lis.Bind( net.SocketAddress( net.Loopback( ), 0 ) )
    dim as long port = lis.LocalAddress( ).Value( ).Port
    dim th as any ptr = threadcreate( @Serve, @lis, 1024 * 1024 )

    dim r as http.HttpResultResponse = http.Fetch( "http://127.0.0.1:" & port & "/greeting" )
    if r.IsOk( ) then
        print r.Value( ).StatusCode; " "; r.Value( ).Reason
        print r.Value( ).Header.Get( "content-type" ).ValueOr( "?" )
        print r.Value( ).Text( )
    end if
    threadwait( th )

    dim bad as http.HttpResultResponse = http.Fetch( "ftp://example.com/file" )
    print bad.Failure( ).Message( )
end sub

Main( )

Output

 200 OK
text/plain
hello, client
Send 'ftp://example.com/file': unsupported URL scheme

The example runs its own tiny server on this machine so that it needs no network: Serve accepts one connection on a second thread, reads the request and writes a reply by hand. That is the whole of HTTP/1.1 on the wire — a status line, headers, a blank line, then the body.

On the client side Header.Get finds a header whatever its case, and returns an Optional, because a header may be missing. Text( ) decodes the body as UTF-8. A status such as 404 is not an error: the request worked and the server answered, so check StatusCode. An error is a request that could not be made at all, like the ftp: URL, which std/http does not speak.

For more than one request make an http.Client: it keeps connections open and reuses them, follows redirects, and holds settings such as TimeoutMs. Client.Open hands the body over as a stream instead of reading it all, for downloads too large to keep in memory.

Activities

  1. Change the server's status line to HTTP/1.1 404 Not Found and print r.Value( ).IsSuccess( ).
  2. Fetch "http://127.0.0.1:1/", where nothing listens, and print the failure's Message( ).