mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-04 09:15:58 +02:00
feat(resources) add http-project-guide
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 1: Getting setup"
|
||||
---
|
||||
|
||||
## Getting setup.
|
||||
|
||||
One of the first steps to any project is having a nice clear workspace to get started.
|
||||
We can do the same with programming projects by creating an empty directory for our project to be developed in.
|
||||
|
||||
You should pick a suitable name for this project, you
|
||||
can pick a word or phrase yourself or use a [project name generator](http://codenames.herokuapp.com/).
|
||||
Try to make sure that there is no space in your project name as this will cause issues later.
|
||||
|
||||
If you are using a build tool that sets up the environment for you now would be a good time to run it.
|
||||
|
||||
Feel free to add the Hello World of your language to test that everything is setup correctly.
|
||||
|
||||
One of the key steps in this project will be to track progress and changes as you develop.
|
||||
For this we are going to be using `git` if you do not know git,
|
||||
don't worry there will be links to [tutorials](https://www.atlassian.com/git/tutorials)
|
||||
and [guides](https://rogerdudler.github.io/git-guide/).
|
||||
|
||||
Setup the git repository and push it to a remote host like Github or Gitlab or BitBucket.
|
||||
|
||||
Consider adding a `.gitignore` file to stop from committing unimportant files.
|
||||
Here is a [guide](https://help.github.com/en/github/using-git/ignoring-files)
|
||||
|
||||
## Goals
|
||||
|
||||
- Pick a name for this project.
|
||||
- Create a new directory on your system.
|
||||
- Create a Hello World.
|
||||
- Initialize a git repository in this directory.
|
||||
- Add any files you need.
|
||||
- Push the repository to a public host.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Create a `.gitignore` file and add that to the repository.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 2: So what are we building?"
|
||||
---
|
||||
|
||||
## Chapter 2: So what are we building?
|
||||
|
||||
The actual final end goal is going to remain a mystery for the time being, but what I can tell you is that we are going
|
||||
to be building a server!
|
||||
|
||||
What is a server? Its a program that accepts incoming connections, reads and writes to that connection and closing
|
||||
it eventually.
|
||||
|
||||
You will hear the term socket used a lot in this project. Sockets are a way of connecting two devices on a network together.
|
||||
One socket listens, the other socket connects.
|
||||
|
||||
The main design of sockets in the unix world is [Berkeley Sockets](https://en.wikipedia.org/wiki/Berkeley_sockets) and
|
||||
on windows its [Winsock](https://www.wikiwand.com/en/Winsock).
|
||||
|
||||
This project will mostly be using berkeley sockets but if you want to use windows APIs feel free.
|
||||
|
||||
In general there is a flow for sockets. On the client you follow a flow like this;
|
||||
|
||||
```txt
|
||||
+---------+
|
||||
| Connect |
|
||||
+---+-----+
|
||||
|
|
||||
+---v--+
|
||||
+---> Send |
|
||||
| +---+--+
|
||||
| |
|
||||
| +---v--+
|
||||
+---+ Recv |
|
||||
+---+--+
|
||||
|
|
||||
+---v---+
|
||||
| Close |
|
||||
+-------+
|
||||
```
|
||||
|
||||
First the client connects. Then the client can send and receive (recv) data until the connection is finally closed.
|
||||
|
||||
On the server the flow is slightly more involved.
|
||||
|
||||
```txt
|
||||
+------+ +--------+ +--------+ +------+ +------+ +-------+
|
||||
| Bind +---> Listen +---> Accept +---> Recv +---> Send +---> Close |
|
||||
+------+ +---^----+ +---+----+ +--^---+ +--+---+ +-------+
|
||||
| | | |
|
||||
+------------+ +----------+
|
||||
```
|
||||
When a server starts up and creates a socket, it binds that socket to an interface and a port.
|
||||
The server will then set the socket to listening for connections,
|
||||
when a connection comes in it needs to accept that connection.
|
||||
Once a connection has been accepted it can receive and send to the socket the same as the client and eventually close it.
|
||||
|
||||
This overview is brushing over a few details and you are encouraged to do your own research
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
- Read up on sockets.
|
||||
- Find the documentation on your languages bindings for sockets.
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 3: Creating a socket"
|
||||
---
|
||||
|
||||
## Chapter 3: Creating a socket.
|
||||
|
||||
Finally some actual code. Lets get started!
|
||||
|
||||
The goal of this chapter is to create a socket and have it listen for connections. This will lay the ground work for future
|
||||
chapters in the project
|
||||
|
||||
The first step is to create a socket in your language.
|
||||
|
||||
Different languages will expect you to set it up in different ways, you should check the documentation for your given
|
||||
network bindings, something like this.
|
||||
|
||||
```js
|
||||
var socket = new Socket();
|
||||
```
|
||||
|
||||
Once we have that socket we can then bind it to an interface.
|
||||
The interface is what IP network / device it is going to listen on, the port is the port it will bind to.
|
||||
|
||||
Whenever you see a connection like `127.0.0.1:6789` the IP address comes first, then `:` then the port number.
|
||||
|
||||
In the pseudo code this would be the required code to bind the socket. You can pick any port number for this, I chose `6789`
|
||||
```js
|
||||
socket.bind("127.0.0.1", 6789);
|
||||
```
|
||||
|
||||
Now that the socket is bound, we can put it into listening mode. Listening mode implies that people will be connecting
|
||||
to this socket. The parameter is *usually* the backlog of connections you want to allow.
|
||||
|
||||
```js
|
||||
socket.listen(1);
|
||||
```
|
||||
|
||||
Once we have set the socket up in listen mode we can finally accept an incoming connection.
|
||||
|
||||
```js
|
||||
var conn = socket.accept();
|
||||
```
|
||||
|
||||
This will accept a connection and hold it.
|
||||
|
||||
You will need to make sure your program doesn't exit prematurely so you might want to have it ask for some standard input or wait on a condition.
|
||||
|
||||
```js
|
||||
var socket = new Socket();
|
||||
socket.bind("127.0.0.1", 6789);
|
||||
socket.listen(1);
|
||||
var conn = socket.accept();
|
||||
|
||||
stdin.read(); // to stop the program just exiting.
|
||||
```
|
||||
|
||||
If you are using windows you can use [Putty](https://www.ssh.com/ssh/putty/putty-manuals/0.68/Chapter3.html#using-rawprot) to create a raw connection.
|
||||
|
||||
On linux you can use `netcat` or `nc` to make network connections,
|
||||
you can see if your server is listening properly by running a command like this
|
||||
|
||||
```sh
|
||||
nc -v -v localhost <port>
|
||||
```
|
||||
|
||||
where `<port>` is the port number you picked earlier on.
|
||||
|
||||
If it works you should see some output like
|
||||
```sh
|
||||
localhost [127.0.0.1] 6789 (radg) open
|
||||
```
|
||||
If something has gone wrong then you will get a different message.
|
||||
|
||||
When you have completed the goals for this chapter you will have created a socket, bound it, listened for connections and accepted a connection.
|
||||
|
||||
You should try experimenting with connecting twice and seeing what happens. This could be something to do with that backlog referenced earlier.
|
||||
|
||||
## Goals
|
||||
|
||||
- Create a socket.
|
||||
- Bind it to an interface and port.
|
||||
- Listen for a single connection.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Allow for a backlog of connections.
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 4: Writing to the socket"
|
||||
---
|
||||
|
||||
## Chapter 4: Writing to the socket.
|
||||
|
||||
We have a server, but it doesn't really do anything. That isn't very useful really.
|
||||
|
||||
In this chapter we will take it a step further and actually write a message to the connection.
|
||||
|
||||
Given our pseudo code from the last chapter,
|
||||
|
||||
```js
|
||||
var socket = new Socket();
|
||||
socket.bind("127.0.0.1", 6789);
|
||||
socket.listen(1);
|
||||
var conn = socket.accept();
|
||||
```
|
||||
|
||||
We now want to be able to write something to this connection.
|
||||
|
||||
Most network bindings will have a `send` or a `write` method. We can call this to send data to the client.
|
||||
|
||||
```js
|
||||
conn.send("Hello Joe!\n");
|
||||
conn.close();
|
||||
```
|
||||
|
||||
When testing this with netcat we should see that when someone connects it prints out `Hello Joe!` in the terminal,
|
||||
then closes the connection.
|
||||
|
||||
For the time being we are going to stick to hard coded responses, but you can change that message to whatever you want.
|
||||
|
||||
You can always send a message to a client that is *not* closed.
|
||||
|
||||
```js
|
||||
conn.send("hi ");
|
||||
conn.send("my name ");
|
||||
conn.send("is ");
|
||||
conn.send("slim shady\n");
|
||||
conn.close();
|
||||
```
|
||||
|
||||
This code will send `hi my name is slim shady` to anyone that connects.
|
||||
Notice it doesn't have to be all in one single send method
|
||||
|
||||
## Goals
|
||||
|
||||
- Write a hello message to a client.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Send a message to the client every X seconds.
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 4: Reading from the socket"
|
||||
---
|
||||
|
||||
## Chapter 4: Reading from the socket.
|
||||
|
||||
Its a good start, we have a server that can accept connections. It will write a message to the client.
|
||||
|
||||
But we aren't reading anything from the client. This will all change now.
|
||||
|
||||
Most network bindings will have a `recv` method. This method allows you to receive some bytes from the client.
|
||||
There might be higher level abstractions like `recv_line` or `recv_all` or something like that but we are gonna focus
|
||||
on the simplest version `recv`. The basic version of recv takes a number, and tries to read that many bytes from the
|
||||
connected client. It will read as many as it can then return what it read.
|
||||
|
||||
Given our code from previous chapters.
|
||||
|
||||
```js
|
||||
var client = socket.accept();
|
||||
client.send("Welcome!\n");
|
||||
var reply = client.recv(4096);
|
||||
client.send("You said: \n");
|
||||
client.send(reply);
|
||||
client.close();
|
||||
```
|
||||
Note that you can also test your server with netcat, use netcat as a client and whatever you write in the terminal will be sent to the server.
|
||||
|
||||
## Goals
|
||||
|
||||
- Read a message from the client.
|
||||
- Write that message back to the client.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Find a method that allows you to read lines OR parse the bytes into lines yourself.
|
||||
- Accept multiple lines.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 6: What is a protocol?"
|
||||
---
|
||||
|
||||
## Chapter 6: What is a protocol?
|
||||
How do we humans communicate? Through a mutually agreed convention of a language and conventions.
|
||||
Similarly, How do we make clients and servers talk to each other?
|
||||
They need some sort of agreed way to ask for things and respond with replies or errors. This mutually agreed set of rules is commonly known as a protocol.
|
||||
|
||||
In this chapter, we are going to create a really simple protocol for getting and storing strings, a *dictionary*.
|
||||
With our hypothetical protocol your server will store the definition to a series of words.
|
||||
You can do this nice and simply with a map like data structure or something more complex, your choice.
|
||||
|
||||
In a client-server architecture, genrally a client initiates communication by making a request to the server. In our case, the client will make a request to *get* a definition from the dictionary server.
|
||||
|
||||
To *get* a definition, the client will send this:
|
||||
```txt
|
||||
GET someword
|
||||
```
|
||||
All lines in this protocol will be terminated with `\n`
|
||||
|
||||
Your server will then look that word up and reply with the value stored against it.
|
||||
The server will need to reply with a sensible error message if the word does not exist.
|
||||
|
||||
For now the reply will be either
|
||||
```txt
|
||||
ANSWER the description
|
||||
```
|
||||
or
|
||||
```txt
|
||||
ERROR can't find someword
|
||||
```
|
||||
We have created a simple reading protocol. This protocol can be extended by adding new requests of the form:
|
||||
```txt
|
||||
VERB args go here
|
||||
```
|
||||
I encourage you to mess about and add other verb based commands.
|
||||
|
||||
## Goals
|
||||
|
||||
- Read `GET word` from the client
|
||||
- Reply `ANSWER definition` to the client
|
||||
- Give errors on undefined words. `ERROR undefined`
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Allow clients to `SET word definition*` at runtime. Where definition might be multiple words ending in `\n`
|
||||
- Add other commands like `CLEAR` to clear all definitions or `ALL` to get all words currently defined.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 7: Testing"
|
||||
---
|
||||
|
||||
## Chapter 7: Testing.
|
||||
Im assuming most of the testing has been done by hand up to this point but this isn't really
|
||||
scalable as a long term solution. This is where unit testing comes in, all projects should have tests that cover
|
||||
at least the bare minimum of cases that are expected. This project is no different.
|
||||
|
||||
Pretty much all languages have some sort of unit test functionality, to make connections and assert things.
|
||||
We will need to write a bit of code to be able to facilitate the unit testing. You will now need to create a
|
||||
tcp client that can connect and you can send and receive lines via, this will help with testing the project as
|
||||
a whole.
|
||||
|
||||
```js
|
||||
fun test_get_definition() {
|
||||
var client = connect("127.0.0.1", 5678);
|
||||
client.send("GET word\n");
|
||||
var line = client.recv(4096);
|
||||
assert(line == "ANSWER something interesting here\n");
|
||||
}
|
||||
```
|
||||
The idea is to try and test all the functionality of your program and use these tests to identify what is going wrong.
|
||||
|
||||
Coverage is a reasonably good metric for establishing if your code is well tested. Coverage is identifying what lines
|
||||
are covered by unit tests and what lines are not.
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
- Unit test any verbs defined in the previous chapter.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Reach a 90% test coverage.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 8: Multiple connections at once"
|
||||
---
|
||||
|
||||
## Chapter 8: Multiple connections at once.
|
||||
|
||||
Up until now we have only had one server, one client.
|
||||
|
||||
If you try to run the server from earlier and connect to it twice you will get one of two things happen. Either the client
|
||||
fails to connect because the server is busy and refuses the connection, or the connection will hang waiting in the backlog
|
||||
to be accepted.
|
||||
|
||||
Now we are going to move to support multiple connections at the same time.
|
||||
|
||||
There are a number of ways to do this; threads, processes, actors, async/await, promises, callbacks, select, iocp. The list can
|
||||
go on for hours. Each language will have different bindings and ways of doing these things, you will need to do some research as to
|
||||
what the best option is for you.
|
||||
|
||||
Both epoll and select are common in most languages a few other suggestions include.
|
||||
|
||||
- Threads in C/C++/Rust
|
||||
- NIO / Threads in Java.
|
||||
- Asyncio / Threads in Python.
|
||||
- Goroutines in Go.
|
||||
- Callbacks / Handlers in Javascript
|
||||
- Actors in Elixir/Erlang
|
||||
|
||||
## Goals
|
||||
|
||||
- Support multiple connections at once.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- See how many connections you can have concurrently using something like [wrk](https://github.com/wg/wrk)
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 9: Documentation and clean code"
|
||||
---
|
||||
|
||||
## Chapter 9: Documentation and clean code.
|
||||
|
||||
Wew this is the chapter nobody wants to talk about.
|
||||
|
||||
A good project is one that is readable and understandable. To be readable code should have some sort of consistency
|
||||
and formatting, this helps with navigation and generally makes working on the code easier. The second is understandable,
|
||||
this comes in two flavours, concise code with clear meaning and documented code with clear explanation.
|
||||
|
||||
Most languages offer some sort of docstring processing, or have support for external tools like doxygen.
|
||||
|
||||
You should take advantage of this and document your code so far, try to explain and design choices and tell the reader
|
||||
what each method does BUT do not go over the top. Nobody wants 500 lines of documentation explaining that `x = 1`.
|
||||
|
||||
## Goals
|
||||
|
||||
- Document and comment your code
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Write a readme.md in your repo
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 10: Methods and resources"
|
||||
---
|
||||
|
||||
## Chapter 10: Methods and resources.
|
||||
|
||||
If you haven't guessed by now, we are writing a HTTP server. Not against the entire specification (though you can if you want)
|
||||
just against a limited subset that *should* work with a browser if you have done it correctly.
|
||||
|
||||
HTTP is a line delimited protocol. The idea being that a client will request content from a server and the server will
|
||||
deliver it.
|
||||
Each time one side delivers a line to the other it should be delimited by `\r` and `\n` which is carriage ret and line feed.
|
||||
|
||||
The start of a HTTP request is as follows.
|
||||
|
||||
```txt
|
||||
[method] [resource] [http-version]\r\n
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
The methods are `OPTIONS` or `GET` or `HEAD` or `POST` or `PUT` or `DELETE` or `TRACE` or `CONNECT`
|
||||
Some of these you might have experienced before, others are a bit more unusual.
|
||||
|
||||
`GET` is the simplest with "GET me this resource". Get is also considered idempotent which means the act of doing it again
|
||||
should have identical results, cause *no* side effects, it can also be cached.
|
||||
|
||||
`PUT` is "PUT something at this resource". This method is also considered idempotent and is usually used to create or update a resource.
|
||||
|
||||
`HEAD` is identical to `GET` but doesn't return the resource, only the headers (more on headers and responses in the next chapter) and start of the request. It is also idempotent.
|
||||
|
||||
`POST` post is explicitly to create new entries at the located resource. It should not be cached and should not be considered idempotent.
|
||||
|
||||
`DELETE` deletes the resource given. It should be repeatable and is considered idempotent.
|
||||
|
||||
`OPTIONS` is kind of a query to see what is allowed on a given resource, it should reply with what methods are supported and any other information.
|
||||
|
||||
`TRACE` and `CONNECT` we are going to ignore these two as they are not commonly used anymore and wont be of much use to us.
|
||||
|
||||
|
||||
### Resource
|
||||
|
||||
A resource is just something identified by a URL. An example of a resource could be `/index.html` or `/api/person`
|
||||
These are both resources, its down to the server to decide what these resources mean. In a web application they might
|
||||
correspond to a controller, or as a file on disk.
|
||||
|
||||
### Version
|
||||
|
||||
The version tells the server what http version the client is using and can support, and the server replies with the same.
|
||||
|
||||
## Goals
|
||||
|
||||
- Process an incoming request (you can use curl, wget, your browser to send requests)
|
||||
- Read the first line and break it into a method, a resource and the version and then close the connection.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Log when a request is invalid (unknown method)
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 11: Headers and bodies"
|
||||
---
|
||||
|
||||
## Chapter 11: Headers and bodies.
|
||||
|
||||
We are almost there, we can almost complete an entire request. But before we can finish a request, we need to
|
||||
read the last few parts of an entire request.
|
||||
|
||||
We have already read the `GET /resource HTTP/1.0\r\n` line parsed.
|
||||
|
||||
The next line following this will be a header line.
|
||||
Headers are just key value pairs that repeat until you read an empty `\r\n` line.
|
||||
You split on the `:` and treat the left hand side as the key, and the right hand side as the value.
|
||||
|
||||
|
||||
This is an example request from curl.
|
||||
```txt
|
||||
GET / HTTP/1.1
|
||||
Host: localhost:9995
|
||||
User-Agent: curl/7.67.0
|
||||
Accept: */*
|
||||
|
||||
```
|
||||
|
||||
This breaks down into the following information.
|
||||
|
||||
* Method: GET
|
||||
* Resource: /
|
||||
* Headers
|
||||
* Host: localhost:9995
|
||||
* User-Agent: curl/7.67.0
|
||||
* Accept: */*
|
||||
|
||||
That's all the information contained in this request.
|
||||
|
||||
There are hundreds of different headers and browsers / clients will often define their own.
|
||||
For a list of common headers look [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
|
||||
|
||||
Some client requests will send a body. This will be included after the header block.
|
||||
For now this is not important.
|
||||
|
||||
## Goals
|
||||
|
||||
- Read an entire request including all the headers.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Handle malformed headers.
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 11: Replying"
|
||||
---
|
||||
|
||||
## Chapter 11: Replying.
|
||||
|
||||
Servers have a number of responses they can make to a request. These range from "OK" to "Not Found" a list can be found [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|
||||
|
||||
The ones we will focus on in this chapter is
|
||||
|
||||
- 200 - OK
|
||||
- 400 - Bad Request
|
||||
- 404 - Not Found
|
||||
|
||||
Lets work through an example
|
||||
|
||||
```txt
|
||||
GET /test.txt HTTP/1.1
|
||||
Host: localhost:9995
|
||||
User-Agent: curl/7.67.0
|
||||
Accept: */*
|
||||
|
||||
```
|
||||
|
||||
Lets start by replying to the request given above.
|
||||
|
||||
For this we need to have a directory for our web hosting files to live in. Lets call this `./www`.
|
||||
Create the directory and add a test file in it called `test.txt` this file should contain some text of your choice.
|
||||
|
||||
Now the request that came in asked for the `test.txt` file we are hosting.
|
||||
So to answer the request we must first check we have that resource, in this case we do.
|
||||
So we are going to reply with the most common HTTP response. OK.
|
||||
|
||||
The first line of the response looks like this. We include the version we support, the status number, and the human readable
|
||||
description of that status number.
|
||||
|
||||
```txt
|
||||
HTTP/1.0 200 OK
|
||||
```
|
||||
|
||||
Once we have sent that line we can send any headers we want to send.
|
||||
There are no mandatory headers but there are some suggested ones we will cover later.
|
||||
|
||||
Then we send an empty `\r\n` to indicate we are done sending the headers. Now we can send the body.
|
||||
|
||||
We read the `test.txt` file in and we write that as the body.
|
||||
Once we are done sending we can simply close the connection to indicate we are done sending the body.
|
||||
|
||||
The entire response might look something like this
|
||||
|
||||
```txt
|
||||
HTTP/1.0 200 OK
|
||||
|
||||
Etiam bibendum sapien ut est posuere pretium. Vestibulum a justo at sapien pharetra sagittis in eget lacus.
|
||||
Sed ullamcorper quam sed nulla molestie interdum. Vestibulum hendrerit, est vel tristique
|
||||
luctus, urna nibh pulvinar ligula, vel scelerisque nisi orci ac mauris. Nam tempor, orci nec rutrum sodales,
|
||||
nulla diam imperdiet enim, id pellentesque leo nibh et urna. Vivamus non tortor dapibus, efficitur ex sed,
|
||||
blandit odio. Vivamus volutpat, nunc sed pulvinar pellentesque, ipsum ante vestibulum sem, vitae malesuada
|
||||
dui odio ut erat.
|
||||
```
|
||||
|
||||
Boom. Done.
|
||||
|
||||
|
||||
There are other replies we might send though, for example lets say someone requests `missing.txt` and we don't have that.
|
||||
We need to inform the client it doesn't exist. We do this by sending a 404. Its mostly the same as the previous but we change
|
||||
the number and message to something different
|
||||
|
||||
```txt
|
||||
HTTP/1.0 404 Not Found
|
||||
|
||||
Sorry we don't have that file!
|
||||
```
|
||||
|
||||
The final response is a generic response when the client sends you something that doesn't make sense.
|
||||
|
||||
Imagine the client sent
|
||||
|
||||
```txt
|
||||
GasdasET /test.txt
|
||||
!!!!!!
|
||||
WHAT/1.1
|
||||
|
||||
```
|
||||
That doesn't look like a valid request so we should tell them that by sending a Bad Request response.
|
||||
|
||||
```txt
|
||||
HTTP/1.0 400 Bad Request
|
||||
|
||||
Im sorry I just don't understand.
|
||||
```
|
||||
|
||||
We can look at once more example this time with headers in the response.
|
||||
|
||||
Lets say we reply and we also want to provide information about the http server that was used. We might send
|
||||
|
||||
```txt
|
||||
HTTP/1.0 200 OK
|
||||
Server: my-awesome-server
|
||||
|
||||
This is my content here.
|
||||
```
|
||||
|
||||
This is an example of the `Server` header, there are other common headers as listed in the link at the top.
|
||||
|
||||
## Goals
|
||||
|
||||
- Read the file asked for by the request and reply with the contents
|
||||
- Add other resources and maybe support directories like `/subdirectory/file.txt`
|
||||
- Reply with a 404 if you can't find the file requested.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Implement the `Content-Length` header
|
||||
- Implement the `Server` header
|
||||
- Implement the `Content-Type` header
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 12: Config"
|
||||
---
|
||||
|
||||
## Chapter 12: Config.
|
||||
|
||||
For the time being we have been hard coding all the various values like the port and the web directory,
|
||||
its about time we made this configurable.
|
||||
|
||||
Lets create a config file that we can set the port and the host in. Lets say this config file is called `config`
|
||||
and can contain any format you want. YAML, JSON, INI, Plain text; whatever suits you and your language.
|
||||
|
||||
For these examples we will use YAML but they are all similar
|
||||
|
||||
```yaml
|
||||
host: localhost
|
||||
port: 9985
|
||||
web_directory: ./www
|
||||
```
|
||||
|
||||
Lets update the program to read the values from config and use those.
|
||||
|
||||
The whole point of making it configurable is the person deploying this in the future doesn't want to edit code or
|
||||
change values in your program to get it to work to their usecase. So by providing a way to configure your application
|
||||
it makes it more portable and usable in different situations.
|
||||
|
||||
This should be quite an easy chapter but its a reasonably important one.
|
||||
|
||||
## Goals
|
||||
|
||||
- Replace any hard coded values with values set in a config file.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Provide sane defaults if the values are missing
|
||||
- Add your own config values.
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: "Chapter 14: Security"
|
||||
---
|
||||
|
||||
## Chapter 14: Security.
|
||||
|
||||
Unless you have spotted it (if you have then well done!) there is already a security risk in our HTTP server.
|
||||
|
||||
Lets look at that now.
|
||||
|
||||
```txt
|
||||
GET /../config.yaml HTTP/1.0
|
||||
|
||||
```
|
||||
|
||||
This request is a relative path. So your server accepts the path. Goes up one directory from the `www` directory.
|
||||
Reads your *config* and sends it to the attacker.
|
||||
|
||||
This is real bad. Imagine if your config had database passwords in it?
|
||||
Imagine if someone requested `../../../../etc/passwd` and your server replied with it!
|
||||
|
||||
This is where security comes in.
|
||||
|
||||
You need to find a way to isolate the `www` directory we created so nobody can read stuff outside of it.
|
||||
|
||||
- You could use some sort of filesystem sandbox like chroot / jails
|
||||
- You could manually work out if `..` will take you above the `www` directory.
|
||||
- You could make the http server run as a different user and only give that user permission to read `www` directory.
|
||||
|
||||
This is just one of many possible attacks against your web server.
|
||||
|
||||
You should look through guides for your language of choice and find ways to harden your application.
|
||||
|
||||
## Goals
|
||||
|
||||
- Solve the ability to read files outside of your `www` directory.
|
||||
|
||||
## Bonus goals
|
||||
|
||||
- Audit your code for other issues.
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
authors:
|
||||
- "Kibb#4205"
|
||||
created_at: 2020/06/08
|
||||
title: HTTP Project Guide
|
||||
---
|
||||
|
||||
## Intro
|
||||
|
||||
Welcome to the TPH first guided project!
|
||||
The goal of this event is to help guide you through the steps of building a self contained project.
|
||||
|
||||
Any questions about the project, goals, or queries can be handled in the event channel.
|
||||
|
||||
You can use any language that the server currently has a channel for.
|
||||
|
||||
This project will expect you to have basic understanding of the language you are using and have a few extra tools
|
||||
installed like; `git`, `netcat` (linux), `putty` (windows)
|
||||
|
||||
This project will guide you in the direction of what you need to do but it leaves individual learning up to you.
|
||||
Feel free to ask for help, search topics online, look for tutorials for any of the concepts presented.
|
||||
|
||||
The idea is to guide you along but not give you all the answers. There will be pseudo code in some of the chapters in
|
||||
this project its down to you to achieve the functionality in your language of choice.
|
||||
The pseudo code isn't representative of a final project and is there to convey specific ideas you need to achieve
|
||||
|
||||
## Rules
|
||||
|
||||
- Put in the work yourself. Don't copy and paste, the only person you are cheating is yourself.
|
||||
- If you are helping don't spoon-feed. Its about the journey not the destination.
|
||||
Reference in New Issue
Block a user