Skip to content

Latest commit

 

History

History
83 lines (54 loc) · 4.14 KB

tiny-http-echo-get.md

File metadata and controls

83 lines (54 loc) · 4.14 KB
title timestamp author published description tags todo
Tiny HTTP: Echo using GET request
2023-12-13 09:10:01 -0800
szabgab
true
A simple GET request, parsing the parameters, returning the text back
tiny_http
web
GET
url
query_pairs
parse
can we improve the get_url_parameters function?

Part of the Tiny HTTP series.

This is a very simple application. When we visit the web site we see a single box where we can type in some text and a button.

When we click the button the server show the same box and button and it also shows You typed and the text we typed in.

This already shows a full round-trip processing of HTTP request and response.

In order to make this work we had to add the url crate so our Cargo.toml now looks like this:

{% include file="examples/tiny-http/echo-get/Cargo.toml" %}

The source code

{% include file="examples/tiny-http/echo-get/src/main.rs" %}

The explanation

There is a function now called get_url_parameters that receives a reference to a tiny_http::Request.

The url method will return the url starting from the initial /. Excluding the protocol that is either http or https, excluding the hostname and excluding the port number. So if we browse to this address:

http://localhost:5000/api/echo?text=Hello+World!&name=Foo%20Bar&text=more%20info

The url method will return

/api/echo?text=Hello+World!&name=Foo%20Bar&text=more%20info

From this we need to extract the part that is after the ? that are the parameters.

I could not figure out how to feed this string to the url crate so I created a fake_url and passed that to the url::Url::parse method.

Using that we go over the pairs returned by query_pairs and we build a hash of vectors. Why vectors and not single values? Because one can supply the same key multiple times on the URL. In our example above we used the "text" field name twice.

I think I could have decided to use the first or the last value in case there are multiple values, but accepting more than one possible values seemed like a more correct solution. This of course will mean that the user of this data structure will have to handle one or more values.

Given this request http://localhost:5000/?text=Hello+World!&name=Foo%20Bar&text=more%20info, these are the params:

{
    "name": ["Foo Bar"],
    "text": ["Hello World!", "more info"]
}

Now let's see the body of the for request in server.incoming_requests() loop.

  • We create the header to be able to set the Content-type to text/html as we have already seen in the Hello World example.
  • The we create a string called html with the HTML form. Embedding HTML in our Rust code is a nasty solution, but I did not want to deal with template system at this point. The variable was made mutable so it will be possible to add the response text.
  • Then we call get_url_parameters described earlier to get the parameters from the URL.
  • Then we have the code to add the reply. When we first visit the web site at http://localhost:5000/ as you can see in the first image, there are no parameters. The params variable will be empty, the text field won't exists and thus the block of the if-statement will be skipped. Once we type in some text in the box and click on the link the HTML form will be sent to the same address, but this time the URL will also include the ?text=Hello+World! part as you can see in the second image. This will be parsed by the get_url_parameters function and we will have a text key in the params variable that will contain a vector of strings. We take the first one and append it to the html variable with some extra text.
  • The last 3 lines in the main function returns the html string with the header.