The Pico/W In C: Simple Web Client
Written by Harry Fairhead   
Monday, 31 October 2022
Article Index
The Pico/W In C: Simple Web Client

The headers_done_fn callback returns the headers and gives you an opportunity to cancel the transfer:

err_t httpc_headers_done_fn(
    httpc_state_t *connection, 
    void *arg, 
    struct pbuf *hdr, 
    u16_t hdr_len,
    u32_t content_len);

The parameters are by now familiar from the other callbacks:


HTTP client connection


Argument specified when initiating the request


pbuf linked list containing headers and perhaps body data.


Length of the headers in 'hdr'


Content length as received in the headers (-1 if not received)


If the callback returns anything but ERR_OK the connection is aborted.

This seems complicated at first, but there are three important callbacks:


Set in call - returns data as a pbuf linked list


Set in settings - returns headers as a pbuf linked list


Set in settings - returns no data, just error codes


We can now write a simple program that retrieves a web page. The simpler of the two HTTP functions is httpc_get_file as it doesn’t involve any DNS system but most web sites don’t respond correctly to a raw IP address. For example, is a standard web site for demonstrating how things work and you can download it using

It is at, but if you try

the result is “file not found”.

Many websites make use of the URL to work out which of a number of possible virtual websites, which reside at the same IP address, you are specifying. As a result it is better to use httpc_get_file_dns, which uses the URL unless you know that the web site you are working with responds correctly to a simple IP address.


To download we first need to set up settings and the three callbacks and make the call to httpc_get_file_dns:

 httpc_connection_t settings;
 settings.result_fn = result;
 settings.headers_done_fn = headers;
 err_t err = httpc_get_file_dns(

You can see that the first three parameters define the web page we want to download and the port. Now we need to define the three callbacks:

void result(void *arg, httpc_result_t httpc_result, 
u32_t rx_content_len, u32_t srv_res, err_t err)
printf("transfer complete\n"); printf("local result=%d\n", httpc_result); printf("http result=%d\n", srv_res); }
err_t headers(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
printf("headers recieved\n");
printf("content length=%d\n", content_len);
printf("header length %d\n", hdr_len);
pbuf_copy_partial(hdr, myBuff, hdr->tot_len, 0);
printf("headers \n");
printf("%s", myBuff);
return ERR_OK;
err_t body(void *arg, struct altcp_pcb *conn,
struct pbuf *p, err_t err)
pbuf_copy_partial(p, myBuff, p->tot_len, 0);
printf("%s", myBuff);
return ERR_OK;

The only part that needs explanation is how the pbuf linked list is processed. A single TCP connection may involve multiple data packets. These are received and assembled into a linked list of buffers – one for each packet. If you know how linked lists work you can write your own code to manipulate it, but in most cases it is easier to use the provided PBUF module and its associated functions. If you examine the documentation, where PBUF is listed under infrastructure, you will find:

u16_t pbuf_copy_partial(
       const struct pbuf *	buf,
       void *	dataptr,
       u16_t 	len,
       u16_t 	offset)		

This will copy all or part of the contents of a packet buffer to an application supplied buffer. This makes it easy to transfer the data in the pbuf into our own simple char buffer:

pbuf_copy_partial(p, myBuff, p->tot_len, 0);

Of course, you have to make sure that mBuff is large enough to hold the data.

Last Updated ( Monday, 23 January 2023 )