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