Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 1 | // Copyright (c) FIRST and other WPILib contributors. |
| 2 | // Open Source Software; you can modify and/or share it under the terms of |
| 3 | // the WPILib BSD license file in the root directory of this project. |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 4 | |
| 5 | #include <cstdio> |
| 6 | |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 7 | #include "fmt/format.h" |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 8 | #include "wpi/EventLoopRunner.h" |
| 9 | #include "wpi/HttpServerConnection.h" |
| 10 | #include "wpi/UrlParser.h" |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 11 | #include "wpi/uv/Loop.h" |
| 12 | #include "wpi/uv/Tcp.h" |
| 13 | |
| 14 | namespace uv = wpi::uv; |
| 15 | |
| 16 | class MyHttpServerConnection : public wpi::HttpServerConnection { |
| 17 | public: |
| 18 | explicit MyHttpServerConnection(std::shared_ptr<uv::Stream> stream) |
| 19 | : HttpServerConnection(stream) {} |
| 20 | |
| 21 | protected: |
| 22 | void ProcessRequest() override; |
| 23 | }; |
| 24 | |
| 25 | void MyHttpServerConnection::ProcessRequest() { |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 26 | fmt::print(stderr, "HTTP request: '{}'\n", m_request.GetUrl()); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 27 | wpi::UrlParser url{m_request.GetUrl(), |
| 28 | m_request.GetMethod() == wpi::HTTP_CONNECT}; |
| 29 | if (!url.IsValid()) { |
| 30 | // failed to parse URL |
| 31 | SendError(400); |
| 32 | return; |
| 33 | } |
| 34 | |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 35 | std::string_view path; |
| 36 | if (url.HasPath()) { |
| 37 | path = url.GetPath(); |
| 38 | } |
| 39 | fmt::print(stderr, "path: \"{}\"\n", path); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 40 | |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 41 | std::string_view query; |
| 42 | if (url.HasQuery()) { |
| 43 | query = url.GetQuery(); |
| 44 | } |
| 45 | fmt::print(stderr, "query: \"{}\"\n", query); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 46 | |
| 47 | const bool isGET = m_request.GetMethod() == wpi::HTTP_GET; |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 48 | if (isGET && path == "/") { |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 49 | // build HTML root page |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 50 | SendResponse(200, "OK", "text/html", |
| 51 | "<html><head><title>WebServer Example</title></head>" |
| 52 | "<body><p>This is an example root page from the webserver." |
| 53 | "</body></html>"); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 54 | } else { |
| 55 | SendError(404, "Resource not found"); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | int main() { |
| 60 | // Kick off the event loop on a separate thread |
| 61 | wpi::EventLoopRunner loop; |
| 62 | loop.ExecAsync([](uv::Loop& loop) { |
| 63 | auto tcp = uv::Tcp::Create(loop); |
| 64 | |
| 65 | // bind to listen address and port |
| 66 | tcp->Bind("", 8080); |
| 67 | |
| 68 | // when we get a connection, accept it and start reading |
| 69 | tcp->connection.connect([srv = tcp.get()] { |
| 70 | auto tcp = srv->Accept(); |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 71 | if (!tcp) { |
| 72 | return; |
| 73 | } |
| 74 | std::fputs("Got a connection\n", stderr); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 75 | auto conn = std::make_shared<MyHttpServerConnection>(tcp); |
| 76 | tcp->SetData(conn); |
| 77 | }); |
| 78 | |
| 79 | // start listening for incoming connections |
| 80 | tcp->Listen(); |
| 81 | |
Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 82 | std::fputs("Listening on port 8080\n", stderr); |
Brian Silverman | 8fce748 | 2020-01-05 13:18:21 -0800 | [diff] [blame] | 83 | }); |
| 84 | |
| 85 | // wait for a keypress to terminate |
| 86 | std::getchar(); |
| 87 | } |