{"id":26690690,"url":"https://github.com/danielcuthbert/archibald","last_synced_at":"2025-03-26T15:34:32.237Z","repository":{"id":37758522,"uuid":"488155218","full_name":"danielcuthbert/archibald","owner":"danielcuthbert","description":"Archibald is my attempt at learning Rust and writing a HTTP 1.1 web server. ","archived":false,"fork":false,"pushed_at":"2024-09-14T10:55:26.000Z","size":4629,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-09-14T21:05:21.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielcuthbert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-03T09:53:35.000Z","updated_at":"2024-09-14T12:30:19.000Z","dependencies_parsed_at":"2023-12-08T11:29:27.239Z","dependency_job_id":"dbc61cc9-d5f0-4c19-a018-11fd3a4dee9b","html_url":"https://github.com/danielcuthbert/archibald","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielcuthbert%2Farchibald","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielcuthbert%2Farchibald/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielcuthbert%2Farchibald/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielcuthbert%2Farchibald/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielcuthbert","download_url":"https://codeload.github.com/danielcuthbert/archibald/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245681834,"owners_count":20655270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-26T15:34:31.547Z","updated_at":"2025-03-26T15:34:32.227Z","avatar_url":"https://github.com/danielcuthbert.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Oh hello](img/isay.png)\n\n# Archibald\n\nTo be a butler, is to be able to maintain an even-temper, at all times. One must have exceptional personal hygiene and look sharp and professional, always. Even when under stress or scrutiny, a butler must remain calm and lead their team through the difficulties.\n\nArchibald is my attempt at learning Rust and writing a HTTP 1.1 web server.\n\n## Architecture\n\n![](img/architecture.png)\n\nWe shall be adopting the KISS approach to building things. I mean how hard is parsing modern web languages and content?\n\n## Threat Modeling\n\n![Oh hello](img/architecture2.png)\n\nI'm sure no-one will dare to attack this, but just in case, we shall be performing a threat modeling exercise so we understand the threats and code appropriate countermeasures.\n\n![Oh hello](img/threats.png)\n\n## How Does HTTP Actually Work?\n\nFor those who aren't aware, Hypertext Transfer Protocol (HTTP) is a [layer 7](https://en.wikipedia.org/wiki/OSI_model) (application) protocol. The whole thing works by requests and responses, the latter being accepted by a server, which provides the answer. HTTP is stateless and this makes it more fun in a way.\n\nIt all looks like this:\n\n```\ndaniel@sexy ~/Code/Archibald -\u003e main -\u003e nc -vv nsa.gov 80\nNotice: Real hostname for nsa.gov [23.63.141.16] is a23-63-141-16.deploy.static.akamaitechnologies.com\nnsa.gov [23.63.141.16] 80 (http) open\nGET / HTTP/1.1\n```\n\nThat's connecting to the server, on port 80 and asking for the index. It responds:\n\n```\nHTTP/1.0 400 Bad Request\nServer: AkamaiGHost\nMime-Version: 1.0\nContent-Type: text/html\nContent-Length: 209\nExpires: Tue, 03 May 2022 13:36:08 GMT\nDate: Tue, 03 May 2022 13:36:08 GMT\nConnection: close\n\n\u003cHTML\u003e\u003cHEAD\u003e\n\u003cTITLE\u003eInvalid URL\u003c/TITLE\u003e\n\u003c/HEAD\u003e\u003cBODY\u003e\n\u003cH1\u003eInvalid URL\u003c/H1\u003e\nThe requested URL \"\u0026#91;no\u0026#32;URL\u0026#93;\", is invalid.\u003cp\u003e\nReference\u0026#32;\u0026#35;9\u0026#46;1ef01602\u0026#46;1651584968\u0026#46;16093878\n\u003c/BODY\u003e\u003c/HTML\u003e\nTotal received bytes: 419\nTotal sent bytes: 16\n```\n\n### Understanding HTTP Messages\n\nThere are two types of HTTP messages, requests and responses, each with its own format.\n\n**Requests**\n\nGET (Method)\n/ (Path)\nHTTP /1.1 (Protocol Version)\n\n**Responses**\n\nHTTP/1.0 (Protocol Version)\n400 (Status Code)\nBad Request (Status Message)\n\nWe need to model the data and understand how best to handle said data.\nUsing the above requests and responses, the data we should expect from a client is:\n\n```\nGET /user/ID/7 HTTP/1.1\\r\\n\nHost: nsa.gov\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\nAccept-Language: en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\n```\n\nIn order to accept and process the request (the GET method), we'd need to store this into a struct of sorts and using the above method, path, protocol, status code, status message, it should handle it properly and in a secure way.\n\nThis might look like:\n\n```\nstruct Request {\n    // We need to store the request body\n    method: String,\n    query: String,\n    path: String,\n    body: String,\n    statuscode: u16,\n    statusmessage: String,\n}\n```\n\nThe above looks good but actually could introduce a bug, for example the HTTP method option could be abused to include payloads other than POST, GET, PUT, PATCH, OPTIONS and DELETE. This needs to be taken into account when designing this struct.\n\nDigging into Rust's capability, it looks like we can solve this by using the [enum](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html) function.\n\n```\nenum Allowedmethods {\n    GET,\n    POST,\n    PUT,\n    DELETE,\n    HEAD,\n    OPTIONS,\n    PATCH,\n    TRACE,\n    CONNECT,\n}\n```\n\nThe pentesters reading this will probably be screaming at me for including OPTIONS and TRACE, but hey you need report fodder right?\n\nBut what happens when someone decides to break the rules and not supply any query string? what sick bastard would do that right?\n\nNormally you would use a NULL but Rust doesn't have that but does have an enum called Option, which can encode the concept of a value being present or absent. Without this, it would probably lead to a [Null-pointer](https://owasp.org/www-community/vulnerabilities/Null_Dereference) dereference vulnerability of sorts.\n\n## Disclaimer\n\nThis will not be production ready, it might eat your children and cause you to like Lotus Notes. I'm not professing to be an expert in Rust and therefore treat this as pretty dodgy.\n\n## ToDo\n\nThere is a lot still that needs doing. Currently the server runs and listens on a port but thats where the fun ends. Here's my roadmap:\n\n1. ~~Respond to requests from clients by looking for a default index.html file in the predefined web root or resource being requested.~~\n2. Correctly validate incoming requests using the validation.rs function.\n3. Implement correct logging for debugging, audit and analysis.\n4. Read configuration files for startup, such as what webroot etc. We can borrow the NGINX format here.\n5. We are currently a single-thread butler. That isn't good so we should have many and std::thread could help here.\n6. We do nothing with headers in both the requests.rs or the response.rs\n\n### Configuration Files\n\nTo make life easier, Archibald reads options from a configuration file. The default configuration file can be found in config/archibald.toml and looks like so:\n\n```\n[config]\nip = \"127.0.0.1\"\nport = 8080\nstatic_path = \"/static_content\"\ndefault_path = \"\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielcuthbert%2Farchibald","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielcuthbert%2Farchibald","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielcuthbert%2Farchibald/lists"}