2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2018-08-20 13:11:39 -07:00
|
|
|
|
|
|
|
|
#include <cstdio>
|
2024-09-20 17:43:39 -07:00
|
|
|
#include <memory>
|
2018-08-20 13:11:39 -07:00
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/net/EventLoopRunner.hpp"
|
|
|
|
|
#include "wpi/net/HttpServerConnection.hpp"
|
|
|
|
|
#include "wpi/net/UrlParser.hpp"
|
|
|
|
|
#include "wpi/net/uv/Loop.hpp"
|
|
|
|
|
#include "wpi/net/uv/Tcp.hpp"
|
2025-11-07 19:57:55 -05:00
|
|
|
#include "wpi/util/print.hpp"
|
2018-08-20 13:11:39 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
namespace uv = wpi::net::uv;
|
2018-08-20 13:11:39 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
class MyHttpServerConnection : public wpi::net::HttpServerConnection {
|
2018-08-20 13:11:39 -07:00
|
|
|
public:
|
|
|
|
|
explicit MyHttpServerConnection(std::shared_ptr<uv::Stream> stream)
|
|
|
|
|
: HttpServerConnection(stream) {}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void ProcessRequest() override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void MyHttpServerConnection::ProcessRequest() {
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::util::print(stderr, "HTTP request: '{}'\n", m_request.GetUrl());
|
|
|
|
|
wpi::net::UrlParser url{m_request.GetUrl(),
|
2025-11-07 20:01:58 -05:00
|
|
|
m_request.GetMethod() == wpi::net::HTTP_CONNECT};
|
2018-08-20 13:11:39 -07:00
|
|
|
if (!url.IsValid()) {
|
|
|
|
|
// failed to parse URL
|
|
|
|
|
SendError(400);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string_view path;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (url.HasPath()) {
|
|
|
|
|
path = url.GetPath();
|
|
|
|
|
}
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::util::print(stderr, "path: \"{}\"\n", path);
|
2018-08-20 13:11:39 -07:00
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string_view query;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (url.HasQuery()) {
|
|
|
|
|
query = url.GetQuery();
|
|
|
|
|
}
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::util::print(stderr, "query: \"{}\"\n", query);
|
2018-08-20 13:11:39 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
const bool isGET = m_request.GetMethod() == wpi::net::HTTP_GET;
|
2021-06-06 16:13:58 -07:00
|
|
|
if (isGET && path == "/") {
|
2018-08-20 13:11:39 -07:00
|
|
|
// build HTML root page
|
2021-06-06 16:13:58 -07:00
|
|
|
SendResponse(200, "OK", "text/html",
|
|
|
|
|
"<html><head><title>WebServer Example</title></head>"
|
|
|
|
|
"<body><p>This is an example root page from the webserver."
|
|
|
|
|
"</body></html>");
|
2018-08-20 13:11:39 -07:00
|
|
|
} else {
|
|
|
|
|
SendError(404, "Resource not found");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
// Kick off the event loop on a separate thread
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::net::EventLoopRunner loop;
|
2018-08-20 13:11:39 -07:00
|
|
|
loop.ExecAsync([](uv::Loop& loop) {
|
|
|
|
|
auto tcp = uv::Tcp::Create(loop);
|
|
|
|
|
|
|
|
|
|
// bind to listen address and port
|
|
|
|
|
tcp->Bind("", 8080);
|
|
|
|
|
|
|
|
|
|
// when we get a connection, accept it and start reading
|
|
|
|
|
tcp->connection.connect([srv = tcp.get()] {
|
|
|
|
|
auto tcp = srv->Accept();
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!tcp) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
std::fputs("Got a connection\n", stderr);
|
2018-08-20 13:11:39 -07:00
|
|
|
auto conn = std::make_shared<MyHttpServerConnection>(tcp);
|
|
|
|
|
tcp->SetData(conn);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// start listening for incoming connections
|
|
|
|
|
tcp->Listen();
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
std::fputs("Listening on port 8080\n", stderr);
|
2018-08-20 13:11:39 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// wait for a keypress to terminate
|
2024-11-12 16:39:41 -08:00
|
|
|
static_cast<void>(std::getchar());
|
2018-08-20 13:11:39 -07:00
|
|
|
}
|