Merge pull request #294 from the-programmers-hangout/style-format-codebase

style: format codebase with Prettier
This commit is contained in:
Jean-Philippe Sirois
2020-07-24 11:05:18 -04:00
committed by GitHub
16 changed files with 130 additions and 117 deletions
@@ -66,18 +66,18 @@ const weather = await getWeatherAsync("Los Angeles").catch((error) => {
console.log(weather); console.log(weather);
``` ```
In Node.js >v8.0.0 you can make use of the built-in `util` package which exposes a In Node.js >v8.0.0 you can make use of the built-in `util` package which exposes a
[promisify](https://nodejs.org/api/util.html#util_util_promisify_original) method. This method helps us convert our original function to a promise-based function so that it returns the callback. [promisify](https://nodejs.org/api/util.html#util_util_promisify_original) method. This method helps us convert our original function to a promise-based function so that it returns the callback.
Using our example from earlier, we can write it as: Using our example from earlier, we can write it as:
```js ```js
const util = require("util") const util = require("util");
const getWeatherAsync = util.promisify(getWeather) const getWeatherAsync = util.promisify(getWeather);
const weather = await getWeatherAync("Los Angeles").catch(console.log) const weather = await getWeatherAync("Los Angeles").catch(console.log);
console.log(weather) console.log(weather);
``` ```
**Note:** the `promisify` method adds a extra argument to the arguments you passed in. In this case we are calling the custom function with a single parameter of type `String`, which means the original function should also accept `(String, Function)`, `Function` being the callback `(error, result)`. **Note:** the `promisify` method adds a extra argument to the arguments you passed in. In this case we are calling the custom function with a single parameter of type `String`, which means the original function should also accept `(String, Function)`, `Function` being the callback `(error, result)`.
@@ -7,10 +7,10 @@ title: "Chapter 1: Getting setup"
## Getting setup. ## Getting setup.
One of the first steps to any project is having a nice clear workspace to get started. 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. 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 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/). 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. Try to make sure that there is no space in your project name as this will cause issues later.
@@ -18,14 +18,14 @@ If you are using a build tool that sets up the environment for you now would be
Feel free to add the Hello World of your language to test that everything is setup correctly. 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. 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, 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) don't worry there will be links to [tutorials](https://www.atlassian.com/git/tutorials)
and [guides](https://rogerdudler.github.io/git-guide/). 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. 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. 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) Here is a [guide](https://help.github.com/en/github/using-git/ignoring-files)
## Goals ## Goals
@@ -39,4 +39,4 @@ Here is a [guide](https://help.github.com/en/github/using-git/ignoring-files)
## Bonus goals ## Bonus goals
- Create a `.gitignore` file and add that to the repository. - Create a `.gitignore` file and add that to the repository.
@@ -10,7 +10,7 @@ title: "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 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! to be building a server!
What is a server? It's a program that accepts incoming connections, reads and writes to that connection and closing What is a server? It's a program that accepts incoming connections, reads and writes to that connection and closing
it eventually. 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. You will hear the term socket used a lot in this project. Sockets are a way of connecting two devices on a network together.
@@ -21,7 +21,7 @@ on windows it's [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. 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; In general there is a flow for sockets. On the client you follow a flow like this;
```txt ```txt
+---------+ +---------+
@@ -52,15 +52,15 @@ On the server the flow is slightly more involved.
| | | | | | | |
+------------+ +----------+ +------------+ +----------+
``` ```
When a server starts up and creates a socket, it binds that socket to an interface and a port. 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, The server will then set the socket to listening for connections,
when a connection comes in it needs to accept that connection. 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. 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 This overview is brushing over a few details and you are encouraged to do your own research
## Goals ## Goals
- Read up on sockets. - Read up on sockets.
- Find the documentation on your languages bindings for sockets. - Find the documentation on your languages bindings for sockets.
@@ -14,31 +14,32 @@ chapters in the project
The first step is to create a socket in your language. 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 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. network bindings, something like this.
```js ```js
var socket = new Socket(); var socket = new Socket();
``` ```
Once we have that socket we can then bind it to an interface. 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. 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. 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` 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 ```js
socket.bind("127.0.0.1", 6789); 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 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. to this socket. The parameter is _usually_ the backlog of connections you want to allow.
```js ```js
socket.listen(1); socket.listen(1);
``` ```
Once we have set the socket up in listen mode we can finally accept an incoming connection. Once we have set the socket up in listen mode we can finally accept an incoming connection.
```js ```js
var conn = socket.accept(); var conn = socket.accept();
@@ -59,19 +60,21 @@ 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. 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, 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 you can see if your server is listening properly by running a command like this
```sh ```sh
nc -v -v localhost <port> nc -v -v localhost <port>
``` ```
where `<port>` is the port number you picked earlier on. where `<port>` is the port number you picked earlier on.
If it works you should see some output like
If it works you should see some output like
```sh ```sh
localhost [127.0.0.1] 6789 (radg) open localhost [127.0.0.1] 6789 (radg) open
``` ```
If something has gone wrong then you will get a different message. 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. When you have completed the goals for this chapter you will have created a socket, bound it, listened for connections and accepted a connection.
@@ -86,4 +89,4 @@ You should try experimenting with connecting twice and seeing what happens. This
## Bonus goals ## Bonus goals
- Allow for a backlog of connections. - Allow for a backlog of connections.
@@ -7,7 +7,7 @@ title: "Chapter 4: Writing to the socket"
## 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. 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. In this chapter we will take it a step further and actually write a message to the connection.
@@ -29,12 +29,12 @@ conn.send("Hello Joe!\n");
conn.close(); conn.close();
``` ```
When testing this with netcat we should see that when someone connects it prints out `Hello Joe!` in the terminal, When testing this with netcat we should see that when someone connects it prints out `Hello Joe!` in the terminal,
then closes the connection. 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. 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. You can always send a message to a client that is _not_ closed.
```js ```js
conn.send("hi "); conn.send("hi ");
@@ -44,7 +44,7 @@ conn.send("slim shady\n");
conn.close(); conn.close();
``` ```
This code will send `hi my name is slim shady` to anyone that connects. 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 Notice it doesn't have to be all in one single send method
## Goals ## Goals
@@ -53,4 +53,4 @@ Notice it doesn't have to be all in one single send method
## Bonus goals ## Bonus goals
- Send a message to the client every X seconds. - Send a message to the client every X seconds.
@@ -7,14 +7,14 @@ title: "Chapter 4: Reading from the socket"
## Chapter 4: Reading from the socket. ## Chapter 4: Reading from the socket.
It's a good start, we have a server that can accept connections. It will write a message to the client. It's 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. 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. 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 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 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. connected client. It will read as many as it can then return what it read.
Given our code from previous chapters. Given our code from previous chapters.
@@ -26,6 +26,7 @@ client.send("You said: \n");
client.send(reply); client.send(reply);
client.close(); 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. 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 ## Goals
@@ -36,4 +37,4 @@ Note that you can also test your server with netcat, use netcat as a client and
## Bonus goals ## Bonus goals
- Find a method that allows you to read lines OR parse the bytes into lines yourself. - Find a method that allows you to read lines OR parse the bytes into lines yourself.
- Accept multiple lines. - Accept multiple lines.
@@ -6,37 +6,46 @@ title: "Chapter 6: What is a protocol?"
--- ---
## 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. 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? 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. 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*. 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. 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. 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. 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:
To *get* a definition, the client will send this:
```txt ```txt
GET someword GET someword
``` ```
All lines in this protocol will be terminated with `\n` 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. 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. The server will need to reply with a sensible error message if the word does not exist.
For now the reply will be either For now the reply will be either
```txt ```txt
ANSWER the description ANSWER the description
``` ```
or
or
```txt ```txt
ERROR can't find someword ERROR can't find someword
``` ```
We have created a simple reading protocol. This protocol can be extended by adding new requests of the form: We have created a simple reading protocol. This protocol can be extended by adding new requests of the form:
```txt ```txt
VERB args go here VERB args go here
``` ```
I encourage you to experiment and add other verb based commands. I encourage you to experiment and add other verb based commands.
## Goals ## Goals
@@ -48,4 +57,4 @@ I encourage you to experiment and add other verb based commands.
## Bonus goals ## Bonus goals
- Allow clients to `SET word definition*` at runtime. Where definition might be multiple words ending in `\n` - 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. - Add other commands like `CLEAR` to clear all definitions or `ALL` to get all words currently defined.
@@ -6,12 +6,13 @@ title: "Chapter 7: Testing"
--- ---
## 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. Im assuming most of the testing has been done by hand up to this point but this isn't really
We will need to write a bit of code to be able to facilitate the unit testing. You will now need to create a 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 tcp client that can connect and you can send and receive lines via, this will help with testing the project as
a whole. a whole.
@@ -23,16 +24,16 @@ fun test_get_definition() {
assert(line == "ANSWER something interesting here\n"); assert(line == "ANSWER something interesting here\n");
} }
``` ```
The idea here is to try and test all the functionality of your program and use the above tests to identify what may be going wrong. The idea here is to try and test all the functionality of your program and use the above tests to identify what may be going wrong.
Coverage is a reasonably good metric for establishing if your code is well tested. Coverage is identifying what lines 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. are covered by unit tests and what lines are not.
## Goals ## Goals
- Unit test any verbs defined in the previous chapter. - Unit test any verbs defined in the previous chapter.
## Bonus goals ## Bonus goals
- Reach a 90% test coverage. - Reach a 90% test coverage.
@@ -7,16 +7,16 @@ title: "Chapter 8: Multiple connections at once"
## Chapter 8: Multiple connections at once. ## Chapter 8: Multiple connections at once.
Up until now we have only had one server, one client. 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 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 fails to connect because the server is busy and refuses the connection, or the connection will hang waiting in the backlog
to be accepted. to be accepted.
Now we are going to move to support multiple connections at the same time. 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 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 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. what the best option is for you.
Both epoll and select are common in most languages a few other suggestions include. Both epoll and select are common in most languages a few other suggestions include.
@@ -34,4 +34,4 @@ Both epoll and select are common in most languages a few other suggestions inclu
## Bonus goals ## Bonus goals
- See how many connections you can have concurrently using something like [wrk](https://github.com/wg/wrk) - See how many connections you can have concurrently using something like [wrk](https://github.com/wg/wrk)
@@ -7,15 +7,15 @@ title: "Chapter 9: Documentation and clean code"
## Chapter 9: Documentation and clean code. ## Chapter 9: Documentation and clean code.
Wew this is the chapter nobody wants to talk about. 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 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, 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. 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. 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 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`. what each method does BUT do not go over the top. Nobody wants 500 lines of documentation explaining that `x = 1`.
## Goals ## Goals
@@ -24,4 +24,4 @@ what each method does BUT do not go over the top. Nobody wants 500 lines of docu
## Bonus goals ## Bonus goals
- Write a readme.md in your repo - Write a readme.md in your repo
@@ -8,10 +8,10 @@ title: "Chapter 10: Methods and resources"
## 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) 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. 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 HTTP is a line delimited protocol. The idea being that a client will request content from a server and the server will
deliver it. 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. 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. The start of a HTTP request is as follows.
@@ -25,8 +25,8 @@ The start of a HTTP request is as follows.
The methods are `OPTIONS` or `GET` or `HEAD` or `POST` or `PUT` or `DELETE` or `TRACE` or `CONNECT` 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. 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 `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. 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. `PUT` is "PUT something at this resource". This method is also considered idempotent and is usually used to create or update a resource.
@@ -40,12 +40,11 @@ should have identical results, cause *no* side effects, it can also be cached.
`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. `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 ### Resource
A resource is just something identified by a URL. An example of a resource could be `/index.html` or `/api/person` 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, it's down to the server to decide what these resources mean. In a web application they might These are both resources, it's 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. correspond to a controller, or as a file on disk.
### Version ### Version
@@ -54,8 +53,8 @@ The version tells the server what http version the client is using and can suppo
## Goals ## Goals
- Process an incoming request (you can use curl, wget, your browser to send requests) - 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. - Read the first line and break it into a method, a resource and the version and then close the connection.
## Bonus goals ## Bonus goals
- Log when a request is invalid (unknown method) - Log when a request is invalid (unknown method)
@@ -7,17 +7,17 @@ title: "Chapter 11: Headers and bodies"
## 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 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. read the last few parts of an entire request.
We have already read the `GET /resource HTTP/1.0\r\n` line parsed. We have already read the `GET /resource HTTP/1.0\r\n` line parsed.
The next line following this will be a header line. 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. 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. 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. This is an example request from curl.
```txt ```txt
GET / HTTP/1.1 GET / HTTP/1.1
Host: localhost:9995 Host: localhost:9995
@@ -28,19 +28,19 @@ Accept: */*
This breaks down into the following information. This breaks down into the following information.
* Method: GET - Method: GET
* Resource: / - Resource: /
* Headers - Headers
* Host: localhost:9995 - Host: localhost:9995
* User-Agent: curl/7.67.0 - User-Agent: curl/7.67.0
* Accept: */* - Accept: _/_
That's all the information contained in this request. That's all the information contained in this request.
There are hundreds of different headers and browsers / clients will often define their own. 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) 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. Some client requests will send a body. This will be included after the header block.
For now this is not important. For now this is not important.
## Goals ## Goals
@@ -49,4 +49,4 @@ For now this is not important.
## Bonus goals ## Bonus goals
- Handle malformed headers. - Handle malformed headers.
@@ -9,7 +9,7 @@ title: "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) 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 The ones we will focus on in this chapter is
- 200 - OK - 200 - OK
- 400 - Bad Request - 400 - Bad Request
@@ -27,11 +27,11 @@ Accept: */*
Lets start by replying to the request given above. 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`. 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. 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. 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 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. 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 The first line of the response looks like this. We include the version we support, the status number, and the human readable
@@ -41,12 +41,12 @@ description of that status number.
HTTP/1.0 200 OK HTTP/1.0 200 OK
``` ```
Once we have sent that line we can send any headers we want to send. 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. 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. 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. 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. 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 The entire response might look something like this
@@ -54,17 +54,16 @@ The entire response might look something like this
```txt ```txt
HTTP/1.0 200 OK HTTP/1.0 200 OK
Etiam bibendum sapien ut est posuere pretium. Vestibulum a justo at sapien pharetra sagittis in eget lacus. 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 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, 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, 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 blandit odio. Vivamus volutpat, nunc sed pulvinar pellentesque, ipsum ante vestibulum sem, vitae malesuada
dui odio ut erat. dui odio ut erat.
``` ```
Boom. Done. Boom. Done.
There are other replies we might send though, for example lets say someone requests `missing.txt` and we don't have that. 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. It's mostly the same as the previous but we change We need to inform the client it doesn't exist. We do this by sending a 404. It's mostly the same as the previous but we change
the number and message to something different the number and message to something different
@@ -75,16 +74,17 @@ HTTP/1.0 404 Not Found
Sorry we don't have that file! 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. The final response is a generic response when the client sends you something that doesn't make sense.
Imagine the client sent Imagine the client sent
```txt ```txt
GasdasET /test.txt GasdasET /test.txt
!!!!!! !!!!!!
WHAT/1.1 WHAT/1.1
``` ```
That doesn't look like a valid request so we should tell them that by sending a Bad Request response. That doesn't look like a valid request so we should tell them that by sending a Bad Request response.
```txt ```txt
@@ -116,4 +116,4 @@ This is an example of the `Server` header, there are other common headers as lis
- Implement the `Content-Length` header - Implement the `Content-Length` header
- Implement the `Server` header - Implement the `Server` header
- Implement the `Content-Type` header - Implement the `Content-Type` header
@@ -7,11 +7,11 @@ title: "Chapter 12: Config"
## 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, For the time being we have been hard coding all the various values like the port and the web directory,
it's about time we made this configurable. it's 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` 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. 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 For these examples we will use YAML but they are all similar
@@ -23,11 +23,11 @@ web_directory: ./www
Lets update the program to read the values from config and use those. 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 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 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. it makes it more portable and usable in different situations.
This should be quite an easy chapter but it's a reasonably important one. This should be quite an easy chapter but it's a reasonably important one.
## Goals ## Goals
@@ -36,4 +36,4 @@ This should be quite an easy chapter but it's a reasonably important one.
## Bonus goals ## Bonus goals
- Provide sane defaults if the values are missing - Provide sane defaults if the values are missing
- Add your own config values. - Add your own config values.
@@ -16,8 +16,8 @@ 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. 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. Reads your _config_ and sends it to the attacker.
This is real bad. Imagine if your config had database passwords in it? 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! Imagine if someone requested `../../../../etc/passwd` and your server replied with it!
@@ -30,14 +30,14 @@ You need to find a way to isolate the `www` directory we created so nobody can r
- You could manually work out if `..` will take you above the `www` directory. - 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. - 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. 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. You should look through guides for your language of choice and find ways to harden your application.
## Goals ## Goals
- Solve the ability to read files outside of your `www` directory. - Solve the ability to read files outside of your `www` directory.
## Bonus goals ## Bonus goals
- Audit your code for other issues. - Audit your code for other issues.
@@ -14,17 +14,17 @@ Any questions about the project, goals, or queries can be handled in the event c
You can use any language that the server currently has a channel for. 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 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) 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. 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. 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 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 it's down to you to achieve the functionality in your language of choice. this project it's 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 The pseudo code isn't representative of a final project and is there to convey specific ideas you need to achieve
## Rules ## Rules
- Put in the work yourself. Don't copy and paste, the only person you are cheating is yourself. - 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. It's about the journey not the destination. - If you are helping don't spoon-feed. It's about the journey not the destination.