mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
Everywhere: Remove LibGemini
This hasn't been maintained (or worked at all) for a long time, and it's not a widely supported protocol, so let's drop it.
This commit is contained in:
parent
e4cd91761d
commit
f2fd8fc928
Notes:
sideshowbarker
2024-07-16 19:17:47 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/f2fd8fc928 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/37
38 changed files with 9 additions and 1041 deletions
|
@ -20,7 +20,7 @@ This process hosts the main HTML/CSS engine (**LibWeb**.) It also runs JavaScrip
|
|||
|
||||
### Process: RequestServer
|
||||
|
||||
This process can use networking protocols (like HTTP, HTTPS, and Gemini) to request files from the outside world. Each **WebContent** process gets its own **RequestServer** to do uploading or downloading on its behalf.
|
||||
This process can use networking protocols (like HTTP or HTTPS) to request files from the outside world. Each **WebContent** process gets its own **RequestServer** to do uploading or downloading on its behalf.
|
||||
|
||||
For DNS lookups, **RequestServer** asks for help from the system's global **LookupServer** service, which handles all outgoing DNS requests.
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <LibIPC/SingleServer.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <RequestServer/ConnectionFromClient.h>
|
||||
#include <RequestServer/GeminiProtocol.h>
|
||||
#include <RequestServer/HttpProtocol.h>
|
||||
#include <RequestServer/HttpsProtocol.h>
|
||||
|
||||
|
@ -37,7 +36,6 @@ ErrorOr<int> service_main(int ipc_socket)
|
|||
|
||||
Core::EventLoop event_loop;
|
||||
|
||||
RequestServer::GeminiProtocol::install();
|
||||
RequestServer::HttpProtocol::install();
|
||||
RequestServer::HttpsProtocol::install();
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ add_executable(headless-browser
|
|||
|
||||
target_include_directories(headless-browser PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_include_directories(headless-browser PRIVATE ${LADYBIRD_SOURCE_DIR}/Userland/)
|
||||
target_link_libraries(headless-browser PRIVATE AK LibCore LibWeb LibWebView LibWebSocket LibCrypto LibFileSystem LibGemini LibHTTP LibImageDecoderClient LibJS LibGfx LibMain LibSQL LibTLS LibIPC LibDiff LibProtocol LibURL)
|
||||
target_link_libraries(headless-browser PRIVATE AK LibCore LibWeb LibWebView LibWebSocket LibCrypto LibFileSystem LibHTTP LibImageDecoderClient LibJS LibGfx LibMain LibSQL LibTLS LibIPC LibDiff LibProtocol LibURL)
|
||||
|
||||
if (ANDROID)
|
||||
include(cmake/AndroidExtras.cmake)
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
<array>
|
||||
<string>http</string>
|
||||
<string>https</string>
|
||||
<string>gemini</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
|
|
|
@ -8,8 +8,6 @@ set(REQUESTSERVER_SOURCES
|
|||
${REQUESTSERVER_SOURCE_DIR}/ConnectionFromClient.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/ConnectionCache.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/Request.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/GeminiRequest.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/GeminiProtocol.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/HttpRequest.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/HttpProtocol.cpp
|
||||
${REQUESTSERVER_SOURCE_DIR}/HttpsRequest.cpp
|
||||
|
@ -33,7 +31,7 @@ target_link_libraries(RequestServer PRIVATE requestserver)
|
|||
|
||||
target_include_directories(requestserver PRIVATE ${LADYBIRD_SOURCE_DIR}/Userland/Services/)
|
||||
target_include_directories(requestserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||
target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView LibWebSocket LibURL LibThreading)
|
||||
target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibHTTP LibIPC LibMain LibTLS LibWebView LibWebSocket LibURL LibThreading)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
# Solaris has socket and networking related functions in two extra libraries
|
||||
target_link_libraries(requestserver PUBLIC nsl socket)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <LibMain/Main.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <RequestServer/ConnectionFromClient.h>
|
||||
#include <RequestServer/GeminiProtocol.h>
|
||||
#include <RequestServer/HttpProtocol.h>
|
||||
#include <RequestServer/HttpsProtocol.h>
|
||||
|
||||
|
@ -59,7 +58,6 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
Core::Platform::register_with_mach_server(mach_server_name);
|
||||
#endif
|
||||
|
||||
RequestServer::GeminiProtocol::install();
|
||||
RequestServer::HttpProtocol::install();
|
||||
RequestServer::HttpsProtocol::install();
|
||||
|
||||
|
|
|
@ -429,7 +429,6 @@ if (BUILD_LAGOM)
|
|||
Compress
|
||||
Crypto
|
||||
Diff
|
||||
Gemini
|
||||
Gfx
|
||||
HTTP
|
||||
ImageDecoderClient
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <LibGemini/Document.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||
{
|
||||
AK::set_debug_enabled(false);
|
||||
auto gemini = StringView(static_cast<unsigned char const*>(data), size);
|
||||
(void)Gemini::Document::parse(gemini, {});
|
||||
return 0;
|
||||
}
|
|
@ -8,7 +8,6 @@ set(FUZZER_TARGETS
|
|||
DeflateCompression
|
||||
DeflateDecompression
|
||||
FlacLoader
|
||||
Gemini
|
||||
GIFLoader
|
||||
GzipDecompression
|
||||
GzipRoundtrip
|
||||
|
@ -76,7 +75,6 @@ set(FUZZER_DEPENDENCIES_DeflateCompression LibCompress)
|
|||
set(FUZZER_DEPENDENCIES_DeflateDecompression LibCompress)
|
||||
set(FUZZER_DEPENDENCIES_ELF LibELF)
|
||||
set(FUZZER_DEPENDENCIES_FlacLoader LibAudio)
|
||||
set(FUZZER_DEPENDENCIES_Gemini LibGemini)
|
||||
set(FUZZER_DEPENDENCIES_GIFLoader LibGfx)
|
||||
set(FUZZER_DEPENDENCIES_GzipDecompression LibCompress)
|
||||
set(FUZZER_DEPENDENCIES_GzipRoundtrip LibCompress)
|
||||
|
|
|
@ -181,7 +181,6 @@ executable("headless-browser") {
|
|||
"//Userland/Libraries/LibCrypto",
|
||||
"//Userland/Libraries/LibDiff",
|
||||
"//Userland/Libraries/LibFileSystem",
|
||||
"//Userland/Libraries/LibGemini",
|
||||
"//Userland/Libraries/LibGfx",
|
||||
"//Userland/Libraries/LibHTTP",
|
||||
"//Userland/Libraries/LibIPC",
|
||||
|
@ -384,7 +383,6 @@ if (current_os != "mac") {
|
|||
"//Userland/Libraries/LibCrypto",
|
||||
"//Userland/Libraries/LibDiff",
|
||||
"//Userland/Libraries/LibFileSystem",
|
||||
"//Userland/Libraries/LibGemini",
|
||||
"//Userland/Libraries/LibGfx",
|
||||
"//Userland/Libraries/LibHTTP",
|
||||
"//Userland/Libraries/LibIDL",
|
||||
|
@ -418,7 +416,6 @@ if (current_os != "mac") {
|
|||
"$root_out_dir/lib/liblagom-crypto.dylib",
|
||||
"$root_out_dir/lib/liblagom-diff.dylib",
|
||||
"$root_out_dir/lib/liblagom-filesystem.dylib",
|
||||
"$root_out_dir/lib/liblagom-gemini.dylib",
|
||||
"$root_out_dir/lib/liblagom-gfx.dylib",
|
||||
"$root_out_dir/lib/liblagom-http.dylib",
|
||||
"$root_out_dir/lib/liblagom-idl.dylib",
|
||||
|
|
|
@ -9,7 +9,6 @@ executable("RequestServer") {
|
|||
"//Userland/Libraries/LibCore",
|
||||
"//Userland/Libraries/LibCrypto",
|
||||
"//Userland/Libraries/LibFileSystem",
|
||||
"//Userland/Libraries/LibGemini",
|
||||
"//Userland/Libraries/LibHTTP",
|
||||
"//Userland/Libraries/LibIPC",
|
||||
"//Userland/Libraries/LibMain",
|
||||
|
@ -22,8 +21,6 @@ executable("RequestServer") {
|
|||
sources = [
|
||||
"//Userland/Services/RequestServer/ConnectionCache.cpp",
|
||||
"//Userland/Services/RequestServer/ConnectionFromClient.cpp",
|
||||
"//Userland/Services/RequestServer/GeminiProtocol.cpp",
|
||||
"//Userland/Services/RequestServer/GeminiRequest.cpp",
|
||||
"//Userland/Services/RequestServer/HttpProtocol.cpp",
|
||||
"//Userland/Services/RequestServer/HttpRequest.cpp",
|
||||
"//Userland/Services/RequestServer/HttpsProtocol.cpp",
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
shared_library("LibGemini") {
|
||||
output_name = "gemini"
|
||||
include_dirs = [ "//Userland/Libraries" ]
|
||||
sources = [
|
||||
"Document.cpp",
|
||||
"GeminiRequest.cpp",
|
||||
"GeminiResponse.cpp",
|
||||
"Job.cpp",
|
||||
"Line.cpp",
|
||||
]
|
||||
deps = [
|
||||
"//AK",
|
||||
"//Userland/Libraries/LibCore",
|
||||
"//Userland/Libraries/LibTLS",
|
||||
"//Userland/Libraries/LibURL",
|
||||
]
|
||||
}
|
|
@ -364,7 +364,6 @@ shared_library("LibWeb") {
|
|||
"//Userland/Libraries/LibAudio",
|
||||
"//Userland/Libraries/LibCore",
|
||||
"//Userland/Libraries/LibCrypto",
|
||||
"//Userland/Libraries/LibGemini",
|
||||
"//Userland/Libraries/LibGfx",
|
||||
"//Userland/Libraries/LibHTTP",
|
||||
"//Userland/Libraries/LibIDL",
|
||||
|
|
|
@ -4,13 +4,11 @@ add_subdirectory(LibAudio)
|
|||
add_subdirectory(LibCompress)
|
||||
add_subdirectory(LibConfig)
|
||||
add_subdirectory(LibCore)
|
||||
add_subdirectory(LibCrypt)
|
||||
add_subdirectory(LibCrypto)
|
||||
add_subdirectory(LibDesktop)
|
||||
add_subdirectory(LibDiff)
|
||||
add_subdirectory(LibFileSystem)
|
||||
add_subdirectory(LibFileSystemAccessClient)
|
||||
add_subdirectory(LibGemini)
|
||||
add_subdirectory(LibGfx)
|
||||
add_subdirectory(LibHTTP)
|
||||
add_subdirectory(LibIDL)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
set(SOURCES
|
||||
Document.cpp
|
||||
GeminiRequest.cpp
|
||||
GeminiResponse.cpp
|
||||
Job.cpp
|
||||
Line.cpp
|
||||
)
|
||||
|
||||
serenity_lib(LibGemini gemini)
|
||||
target_link_libraries(LibGemini PRIVATE LibCore LibTLS LibURL)
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGemini/Document.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
ByteString Document::render_to_html() const
|
||||
{
|
||||
StringBuilder html_builder;
|
||||
html_builder.append("<!DOCTYPE html>\n<html>\n"sv);
|
||||
html_builder.append("<head>\n<title>"sv);
|
||||
html_builder.append(m_url.serialize_path());
|
||||
html_builder.append("</title>\n</head>\n"sv);
|
||||
html_builder.append("<body>\n"sv);
|
||||
for (auto& line : m_lines) {
|
||||
html_builder.append(line->render_to_html());
|
||||
}
|
||||
html_builder.append("</body>"sv);
|
||||
html_builder.append("</html>"sv);
|
||||
return html_builder.to_byte_string();
|
||||
}
|
||||
|
||||
NonnullRefPtr<Document> Document::parse(StringView lines, const URL::URL& url)
|
||||
{
|
||||
auto document = adopt_ref(*new Document(url));
|
||||
document->read_lines(lines);
|
||||
return document;
|
||||
}
|
||||
|
||||
void Document::read_lines(StringView source)
|
||||
{
|
||||
auto close_list_if_needed = [&] {
|
||||
if (m_inside_unordered_list) {
|
||||
m_inside_unordered_list = false;
|
||||
m_lines.append(make<Control>(Control::UnorderedListEnd));
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& line : source.lines()) {
|
||||
if (line.starts_with("```"sv)) {
|
||||
close_list_if_needed();
|
||||
|
||||
m_inside_preformatted_block = !m_inside_preformatted_block;
|
||||
if (m_inside_preformatted_block) {
|
||||
m_lines.append(make<Control>(Control::PreformattedStart));
|
||||
} else {
|
||||
m_lines.append(make<Control>(Control::PreformattedEnd));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_inside_preformatted_block) {
|
||||
m_lines.append(make<Preformatted>(move(line)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.starts_with('*')) {
|
||||
if (!m_inside_unordered_list)
|
||||
m_lines.append(make<Control>(Control::UnorderedListStart));
|
||||
m_lines.append(make<UnorderedList>(move(line)));
|
||||
m_inside_unordered_list = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
close_list_if_needed();
|
||||
|
||||
if (line.starts_with("=>"sv)) {
|
||||
m_lines.append(make<Link>(move(line), *this));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.starts_with('#')) {
|
||||
size_t level = 0;
|
||||
while (line.length() > level && line[level] == '#')
|
||||
++level;
|
||||
|
||||
m_lines.append(make<Heading>(move(line), level));
|
||||
continue;
|
||||
}
|
||||
|
||||
m_lines.append(make<Text>(move(line)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibURL/URL.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
class Line {
|
||||
public:
|
||||
Line(ByteString string)
|
||||
: m_text(move(string))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Line() = default;
|
||||
|
||||
virtual ByteString render_to_html() const = 0;
|
||||
|
||||
protected:
|
||||
ByteString m_text;
|
||||
};
|
||||
|
||||
class Document : public RefCounted<Document> {
|
||||
public:
|
||||
ByteString render_to_html() const;
|
||||
|
||||
static NonnullRefPtr<Document> parse(StringView source, const URL::URL&);
|
||||
|
||||
const URL::URL& url() const { return m_url; }
|
||||
|
||||
private:
|
||||
explicit Document(const URL::URL& url)
|
||||
: m_url(url)
|
||||
{
|
||||
}
|
||||
|
||||
void read_lines(StringView);
|
||||
|
||||
Vector<NonnullOwnPtr<Line>> m_lines;
|
||||
URL::URL m_url;
|
||||
bool m_inside_preformatted_block { false };
|
||||
bool m_inside_unordered_list { false };
|
||||
};
|
||||
|
||||
class Text : public Line {
|
||||
public:
|
||||
Text(ByteString line)
|
||||
: Line(move(line))
|
||||
{
|
||||
}
|
||||
virtual ~Text() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
};
|
||||
|
||||
class Link : public Line {
|
||||
public:
|
||||
Link(ByteString line, Document const&);
|
||||
virtual ~Link() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
|
||||
private:
|
||||
URL::URL m_url;
|
||||
ByteString m_name;
|
||||
};
|
||||
|
||||
class Preformatted : public Line {
|
||||
public:
|
||||
Preformatted(ByteString line)
|
||||
: Line(move(line))
|
||||
{
|
||||
}
|
||||
virtual ~Preformatted() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
};
|
||||
|
||||
class UnorderedList : public Line {
|
||||
public:
|
||||
UnorderedList(ByteString line)
|
||||
: Line(move(line))
|
||||
{
|
||||
}
|
||||
virtual ~UnorderedList() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
};
|
||||
|
||||
class Control : public Line {
|
||||
public:
|
||||
enum Kind {
|
||||
UnorderedListStart,
|
||||
UnorderedListEnd,
|
||||
PreformattedStart,
|
||||
PreformattedEnd,
|
||||
};
|
||||
Control(Kind kind)
|
||||
: Line("")
|
||||
, m_kind(kind)
|
||||
{
|
||||
}
|
||||
virtual ~Control() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
};
|
||||
|
||||
class Heading : public Line {
|
||||
public:
|
||||
Heading(ByteString line, int level)
|
||||
: Line(move(line))
|
||||
, m_level(level)
|
||||
{
|
||||
}
|
||||
virtual ~Heading() override = default;
|
||||
virtual ByteString render_to_html() const override;
|
||||
|
||||
private:
|
||||
int m_level { 1 };
|
||||
};
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
class Document;
|
||||
class GeminiRequest;
|
||||
class GeminiResponse;
|
||||
class Job;
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibGemini/GeminiRequest.h>
|
||||
#include <LibURL/URL.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
ErrorOr<ByteBuffer> GeminiRequest::to_raw_request() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
TRY(builder.try_append(m_url.to_byte_string()));
|
||||
TRY(builder.try_append("\r\n"sv));
|
||||
return builder.to_byte_buffer();
|
||||
}
|
||||
|
||||
Optional<GeminiRequest> GeminiRequest::from_raw_request(ByteBuffer const& raw_request)
|
||||
{
|
||||
URL::URL url = StringView(raw_request);
|
||||
if (!url.is_valid())
|
||||
return {};
|
||||
GeminiRequest request;
|
||||
request.m_url = url;
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibURL/URL.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
class GeminiRequest {
|
||||
public:
|
||||
GeminiRequest() = default;
|
||||
~GeminiRequest() = default;
|
||||
|
||||
const URL::URL& url() const { return m_url; }
|
||||
void set_url(const URL::URL& url) { m_url = url; }
|
||||
|
||||
ErrorOr<ByteBuffer> to_raw_request() const;
|
||||
|
||||
static Optional<GeminiRequest> from_raw_request(ByteBuffer const&);
|
||||
|
||||
private:
|
||||
URL::URL m_url;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGemini/GeminiResponse.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
GeminiResponse::GeminiResponse(int status, ByteString meta)
|
||||
: m_status(status)
|
||||
, m_meta(meta)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <LibCore/NetworkResponse.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
class GeminiResponse : public Core::NetworkResponse {
|
||||
public:
|
||||
virtual ~GeminiResponse() override = default;
|
||||
static NonnullRefPtr<GeminiResponse> create(int status, ByteString meta)
|
||||
{
|
||||
return adopt_ref(*new GeminiResponse(status, meta));
|
||||
}
|
||||
|
||||
int status() const { return m_status; }
|
||||
ByteString meta() const { return m_meta; }
|
||||
|
||||
private:
|
||||
GeminiResponse(int status, ByteString);
|
||||
|
||||
int m_status { 0 };
|
||||
ByteString m_meta;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,283 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGemini/GeminiResponse.h>
|
||||
#include <LibGemini/Job.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
Job::Job(GeminiRequest const& request, Stream& output_stream)
|
||||
: Core::NetworkJob(output_stream)
|
||||
, m_request(request)
|
||||
{
|
||||
}
|
||||
|
||||
void Job::start(Core::BufferedSocketBase& socket)
|
||||
{
|
||||
VERIFY(!m_socket);
|
||||
m_socket = &socket;
|
||||
on_socket_connected();
|
||||
}
|
||||
|
||||
void Job::shutdown(ShutdownMode mode)
|
||||
{
|
||||
if (!m_socket)
|
||||
return;
|
||||
if (mode == ShutdownMode::CloseSocket) {
|
||||
m_socket->close();
|
||||
} else {
|
||||
m_socket->on_ready_to_read = nullptr;
|
||||
m_socket = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Job::register_on_ready_to_read(Function<void()> callback)
|
||||
{
|
||||
m_socket->on_ready_to_read = [this, callback = move(callback)] {
|
||||
callback();
|
||||
|
||||
while (can_read()) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool Job::can_read_line() const
|
||||
{
|
||||
return MUST(m_socket->can_read_line());
|
||||
}
|
||||
|
||||
ErrorOr<String> Job::read_line(size_t size)
|
||||
{
|
||||
ByteBuffer buffer = TRY(ByteBuffer::create_uninitialized(size));
|
||||
auto bytes_read = TRY(m_socket->read_until(buffer, "\r\n"sv));
|
||||
return String::from_utf8(StringView { bytes_read.data(), bytes_read.size() });
|
||||
}
|
||||
|
||||
ErrorOr<ByteBuffer> Job::receive(size_t size)
|
||||
{
|
||||
ByteBuffer buffer = TRY(ByteBuffer::create_uninitialized(size));
|
||||
auto nread = TRY(m_socket->read_some(buffer)).size();
|
||||
return buffer.slice(0, nread);
|
||||
}
|
||||
|
||||
bool Job::can_read() const
|
||||
{
|
||||
return MUST(m_socket->can_read_without_blocking());
|
||||
}
|
||||
|
||||
bool Job::write(ReadonlyBytes bytes)
|
||||
{
|
||||
return !m_socket->write_until_depleted(bytes).is_error();
|
||||
}
|
||||
|
||||
void Job::flush_received_buffers()
|
||||
{
|
||||
for (size_t i = 0; i < m_received_buffers.size(); ++i) {
|
||||
auto& payload = m_received_buffers[i];
|
||||
auto result = do_write(payload);
|
||||
if (result.is_error()) {
|
||||
if (!result.error().is_errno()) {
|
||||
dbgln("Job: Failed to flush received buffers: {}", result.error());
|
||||
continue;
|
||||
}
|
||||
if (result.error().code() == EINTR) {
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
auto written = result.release_value();
|
||||
m_buffered_size -= written;
|
||||
if (written == payload.size()) {
|
||||
// FIXME: Make this a take-first-friendly object?
|
||||
m_received_buffers.take_first();
|
||||
continue;
|
||||
}
|
||||
VERIFY(written < payload.size());
|
||||
// FIXME: Propagate errors.
|
||||
payload = MUST(payload.slice(written, payload.size() - written));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Job::on_socket_connected()
|
||||
{
|
||||
auto raw_request = m_request.to_raw_request().release_value_but_fixme_should_propagate_errors();
|
||||
|
||||
if constexpr (JOB_DEBUG) {
|
||||
dbgln("Job: raw_request:");
|
||||
dbgln("{}", ByteString::copy(raw_request));
|
||||
}
|
||||
bool success = write(raw_request);
|
||||
if (!success)
|
||||
deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
|
||||
|
||||
register_on_ready_to_read([this] {
|
||||
if (is_cancelled())
|
||||
return;
|
||||
if (m_state == State::Failed)
|
||||
return;
|
||||
|
||||
// https://gemini.circumlunar.space/docs/specification.gmi
|
||||
|
||||
if (m_state == State::InStatus) {
|
||||
if (!can_read_line())
|
||||
return;
|
||||
|
||||
auto line_or_error = read_line(PAGE_SIZE);
|
||||
if (line_or_error.is_error()) {
|
||||
dbgln("Job: Error getting status line {}", line_or_error.error());
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
|
||||
}
|
||||
|
||||
auto line = line_or_error.release_value();
|
||||
auto view = line.bytes_as_string_view();
|
||||
|
||||
auto first_code_point = line.code_points().begin().peek();
|
||||
if (!first_code_point.has_value()) {
|
||||
dbgln("Job: empty status line");
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
if (first_code_point.release_value() == 0xFEFF) {
|
||||
dbgln("Job: Byte order mark as first character of status line");
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
auto maybe_space_index = view.find(' ');
|
||||
if (!maybe_space_index.has_value()) {
|
||||
dbgln("Job: Expected 2-part status line, got '{}'", line);
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
auto space_index = maybe_space_index.release_value();
|
||||
auto first_part = view.substring_view(0, space_index);
|
||||
auto second_part = view.substring_view(space_index + 1);
|
||||
|
||||
auto status = first_part.to_number<unsigned>();
|
||||
if (!status.has_value()) {
|
||||
dbgln("Job: Expected numeric status code");
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
auto meta_first_code_point = Utf8View(second_part).begin().peek();
|
||||
if (meta_first_code_point.release_value() == 0xFEFF) {
|
||||
dbgln("Job: Byte order mark as first character of meta");
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
if (second_part.length() > 1024) {
|
||||
dbgln("Job: Meta too long");
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
m_status = status.release_value();
|
||||
m_meta = second_part;
|
||||
|
||||
if (m_status >= 10 && m_status < 20) {
|
||||
m_state = State::Finished;
|
||||
} else if (m_status >= 20 && m_status < 30) {
|
||||
m_state = State::InBody;
|
||||
} else if (m_status >= 30 && m_status < 40) {
|
||||
m_state = State::Finished;
|
||||
} else if (m_status >= 40 && m_status < 50) {
|
||||
m_state = State::Finished;
|
||||
} else if (m_status >= 50 && m_status < 60) {
|
||||
m_state = State::Finished;
|
||||
} else if (m_status >= 60 && m_status < 70) {
|
||||
m_state = State::InBody;
|
||||
} else {
|
||||
dbgln("Job: Expected status between 10 and 69; instead got {}", m_status);
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::ProtocolFailed); });
|
||||
}
|
||||
|
||||
if (!can_read()) {
|
||||
dbgln("Can't read further :(");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(m_state == State::InBody || m_state == State::Finished);
|
||||
|
||||
while (MUST(m_socket->can_read_without_blocking())) {
|
||||
auto read_size = 64 * KiB;
|
||||
|
||||
auto payload_or_error = receive(read_size);
|
||||
if (payload_or_error.is_error()) {
|
||||
dbgln("Job: Error in receive {}", payload_or_error.error());
|
||||
m_state = State::Failed;
|
||||
return deferred_invoke([this] { did_fail(Core::NetworkJob::Error::TransmissionFailed); });
|
||||
}
|
||||
auto payload = payload_or_error.release_value();
|
||||
|
||||
if (payload.is_empty()) {
|
||||
if (m_socket->is_eof()) {
|
||||
finish_up();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_received_size += payload.size();
|
||||
m_buffered_size += payload.size();
|
||||
m_received_buffers.append(move(payload));
|
||||
flush_received_buffers();
|
||||
|
||||
deferred_invoke([this] { did_progress({}, m_received_size); });
|
||||
|
||||
if (m_socket->is_eof())
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_socket->is_open() || m_socket->is_eof()) {
|
||||
dbgln_if(JOB_DEBUG, "Connection appears to have closed, finishing up");
|
||||
finish_up();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Job::finish_up()
|
||||
{
|
||||
m_state = State::Finished;
|
||||
flush_received_buffers();
|
||||
if (m_buffered_size != 0) {
|
||||
// We have to wait for the client to consume all the downloaded data
|
||||
// before we can actually call `did_finish`. in a normal flow, this should
|
||||
// never be hit since the client is reading as we are writing, unless there
|
||||
// are too many concurrent downloads going on.
|
||||
deferred_invoke([this] {
|
||||
finish_up();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
auto response = GeminiResponse::create(m_status, m_meta);
|
||||
deferred_invoke([this, response] {
|
||||
did_finish(move(response));
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<size_t> Job::response_length() const
|
||||
{
|
||||
if (m_state != State::Finished)
|
||||
return AK::Error::from_string_literal("Gemini response has not finished");
|
||||
|
||||
return m_received_size;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibCore/NetworkJob.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibGemini/GeminiRequest.h>
|
||||
#include <LibGemini/GeminiResponse.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
class Job : public Core::NetworkJob {
|
||||
C_OBJECT(Job);
|
||||
|
||||
public:
|
||||
explicit Job(GeminiRequest const&, Stream&);
|
||||
virtual ~Job() override = default;
|
||||
|
||||
virtual void start(Core::BufferedSocketBase&) override;
|
||||
virtual void shutdown(ShutdownMode) override;
|
||||
|
||||
GeminiResponse* response() { return static_cast<GeminiResponse*>(Core::NetworkJob::response()); }
|
||||
GeminiResponse const* response() const { return static_cast<GeminiResponse const*>(Core::NetworkJob::response()); }
|
||||
|
||||
const URL::URL& url() const { return m_request.url(); }
|
||||
Core::Socket const* socket() const { return m_socket; }
|
||||
|
||||
ErrorOr<size_t> response_length() const;
|
||||
|
||||
protected:
|
||||
void finish_up();
|
||||
void on_socket_connected();
|
||||
void flush_received_buffers();
|
||||
void register_on_ready_to_read(Function<void()>);
|
||||
bool can_read_line() const;
|
||||
ErrorOr<String> read_line(size_t);
|
||||
bool can_read() const;
|
||||
ErrorOr<ByteBuffer> receive(size_t);
|
||||
bool write(ReadonlyBytes);
|
||||
|
||||
enum class State {
|
||||
InStatus,
|
||||
InBody,
|
||||
Finished,
|
||||
Failed,
|
||||
};
|
||||
|
||||
GeminiRequest m_request;
|
||||
State m_state { State::InStatus };
|
||||
int m_status { -1 };
|
||||
ByteString m_meta;
|
||||
Vector<ByteBuffer, 2> m_received_buffers;
|
||||
size_t m_received_size { 0 };
|
||||
size_t m_buffered_size { 0 };
|
||||
Core::BufferedSocketBase* m_socket { nullptr };
|
||||
};
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibGemini/Document.h>
|
||||
|
||||
namespace Gemini {
|
||||
|
||||
ByteString Text::render_to_html() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append(escape_html_entities(m_text));
|
||||
builder.append("<br>\n"sv);
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
ByteString Heading::render_to_html() const
|
||||
{
|
||||
return ByteString::formatted("<h{}>{}</h{}>", m_level, escape_html_entities(m_text.substring_view(m_level, m_text.length() - m_level)), m_level);
|
||||
}
|
||||
|
||||
ByteString UnorderedList::render_to_html() const
|
||||
{
|
||||
// 1.3.5.4.2 "Advanced clients can take the space of the bullet symbol into account"
|
||||
// FIXME: The spec is unclear about what the space means, or where it goes
|
||||
// somehow figure this out
|
||||
StringBuilder builder;
|
||||
builder.append("<li>"sv);
|
||||
builder.append(escape_html_entities(m_text.substring_view(1, m_text.length() - 1)));
|
||||
builder.append("</li>"sv);
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
ByteString Control::render_to_html() const
|
||||
{
|
||||
switch (m_kind) {
|
||||
case Kind::PreformattedEnd:
|
||||
return "</pre>";
|
||||
case Kind::PreformattedStart:
|
||||
return "<pre>";
|
||||
case Kind::UnorderedListStart:
|
||||
return "<ul>";
|
||||
case Kind::UnorderedListEnd:
|
||||
return "</ul>";
|
||||
default:
|
||||
dbgln("Unknown control kind _{}_", (int)m_kind);
|
||||
VERIFY_NOT_REACHED();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Link::Link(ByteString text, Document const& document)
|
||||
: Line(move(text))
|
||||
{
|
||||
size_t index = 2;
|
||||
while (index < m_text.length() && (m_text[index] == ' ' || m_text[index] == '\t'))
|
||||
++index;
|
||||
auto url_string = m_text.substring_view(index, m_text.length() - index);
|
||||
auto space_offset = url_string.find_any_of(" \t"sv);
|
||||
ByteString url = url_string;
|
||||
if (space_offset.has_value()) {
|
||||
url = url_string.substring_view(0, space_offset.value());
|
||||
auto offset = space_offset.value();
|
||||
while (offset < url_string.length() && (url_string[offset] == ' ' || url_string[offset] == '\t'))
|
||||
++offset;
|
||||
m_name = url_string.substring_view(offset, url_string.length() - offset);
|
||||
}
|
||||
m_url = document.url().complete_url(url);
|
||||
if (m_name.is_empty())
|
||||
m_name = m_url.to_byte_string();
|
||||
}
|
||||
|
||||
ByteString Link::render_to_html() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append("<a href=\""sv);
|
||||
builder.append(escape_html_entities(m_url.to_byte_string()));
|
||||
builder.append("\">"sv);
|
||||
builder.append(escape_html_entities(m_name));
|
||||
builder.append("</a><br>\n"sv);
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
ByteString Preformatted::render_to_html() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append(escape_html_entities(m_text));
|
||||
builder.append('\n');
|
||||
|
||||
return builder.to_byte_string();
|
||||
}
|
||||
|
||||
}
|
|
@ -172,8 +172,6 @@ Optional<u16> default_port_for_scheme(StringView scheme)
|
|||
return 443;
|
||||
|
||||
// NOTE: not in spec, but we support these too
|
||||
if (scheme == "gemini")
|
||||
return 1965;
|
||||
if (scheme == "irc")
|
||||
return 6667;
|
||||
if (scheme == "ircs")
|
||||
|
|
|
@ -750,7 +750,7 @@ set(GENERATED_SOURCES
|
|||
|
||||
serenity_lib(LibWeb web)
|
||||
|
||||
target_link_libraries(LibWeb PRIVATE LibCore LibCrypto LibJS LibHTTP LibGemini LibGfx LibIPC LibLocale LibRegex LibSyntax LibTextCodec LibUnicode LibAudio LibVideo LibWasm LibXML LibIDL LibURL LibTLS)
|
||||
target_link_libraries(LibWeb PRIVATE LibCore LibCrypto LibJS LibHTTP LibGfx LibIPC LibLocale LibRegex LibSyntax LibTextCodec LibUnicode LibAudio LibVideo LibWasm LibXML LibIDL LibURL LibTLS)
|
||||
|
||||
if (HAS_ACCELERATED_GRAPHICS)
|
||||
target_link_libraries(LibWeb PRIVATE ${ACCEL_GFX_LIBS})
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibGemini/Document.h>
|
||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||
#include <LibTextCodec/Decoder.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
|
|
|
@ -411,7 +411,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
|
|||
return;
|
||||
}
|
||||
|
||||
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") {
|
||||
if (url.scheme() == "http" || url.scheme() == "https") {
|
||||
auto protocol_request = start_network_request(request);
|
||||
if (!protocol_request) {
|
||||
if (error_callback)
|
||||
|
@ -471,7 +471,7 @@ void ResourceLoader::load_unbuffered(LoadRequest& request, OnHeadersReceived on_
|
|||
return;
|
||||
}
|
||||
|
||||
if (!url.scheme().is_one_of("http"sv, "https"sv, "gemini"sv)) {
|
||||
if (!url.scheme().is_one_of("http"sv, "https"sv)) {
|
||||
// FIXME: Non-network requests from fetch should not go through this path.
|
||||
on_complete(false, "Cannot establish connection non-network scheme"sv);
|
||||
return;
|
||||
|
|
|
@ -154,7 +154,7 @@ Optional<URLParts> break_url_into_parts(StringView url_string)
|
|||
|
||||
if (url.scheme() == "file"sv)
|
||||
return break_file_url_into_parts(url, url_string);
|
||||
if (url.scheme().is_one_of("http"sv, "https"sv, "gemini"sv))
|
||||
if (url.scheme().is_one_of("http"sv, "https"sv))
|
||||
return break_web_url_into_parts(url, url_string);
|
||||
|
||||
return {};
|
||||
|
|
|
@ -10,8 +10,6 @@ set(SOURCES
|
|||
ConnectionFromClient.cpp
|
||||
ConnectionCache.cpp
|
||||
Request.cpp
|
||||
GeminiRequest.cpp
|
||||
GeminiProtocol.cpp
|
||||
HttpRequest.cpp
|
||||
HttpProtocol.cpp
|
||||
HttpsRequest.cpp
|
||||
|
@ -26,4 +24,4 @@ set(GENERATED_SOURCES
|
|||
)
|
||||
|
||||
serenity_bin(RequestServer)
|
||||
target_link_libraries(RequestServer PRIVATE LibCore LibCrypto LibIPC LibGemini LibHTTP LibMain LibTLS LibWebSocket LibURL LibThreading)
|
||||
target_link_libraries(RequestServer PRIVATE LibCore LibCrypto LibIPC LibHTTP LibMain LibTLS LibWebSocket LibURL LibThreading)
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace RequestServer {
|
|||
|
||||
class ConnectionFromClient;
|
||||
class Request;
|
||||
class GeminiProtocol;
|
||||
class HttpRequest;
|
||||
class HttpProtocol;
|
||||
class HttpsRequest;
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "ConnectionCache.h"
|
||||
#include <LibGemini/GeminiRequest.h>
|
||||
#include <LibGemini/Job.h>
|
||||
#include <RequestServer/GeminiProtocol.h>
|
||||
#include <RequestServer/GeminiRequest.h>
|
||||
|
||||
namespace RequestServer {
|
||||
|
||||
GeminiProtocol::GeminiProtocol()
|
||||
: Protocol("gemini")
|
||||
{
|
||||
}
|
||||
|
||||
OwnPtr<Request> GeminiProtocol::start_request(i32 request_id, ConnectionFromClient& client, ByteString const&, const URL::URL& url, HashMap<ByteString, ByteString> const&, ReadonlyBytes, Core::ProxyData proxy_data)
|
||||
{
|
||||
Gemini::GeminiRequest request;
|
||||
request.set_url(url);
|
||||
|
||||
auto pipe_result = get_pipe_for_request();
|
||||
if (pipe_result.is_error())
|
||||
return {};
|
||||
|
||||
auto output_stream = MUST(Core::File::adopt_fd(pipe_result.value().write_fd, Core::File::OpenMode::Write));
|
||||
auto job = Gemini::Job::construct(request, *output_stream);
|
||||
auto protocol_request = GeminiRequest::create_with_job({}, client, *job, move(output_stream), request_id);
|
||||
protocol_request->set_request_fd(pipe_result.value().read_fd);
|
||||
|
||||
Core::EventLoop::current().deferred_invoke([=] {
|
||||
ConnectionCache::ensure_connection(ConnectionCache::g_tls_connection_cache, url, job, proxy_data);
|
||||
});
|
||||
|
||||
return protocol_request;
|
||||
}
|
||||
|
||||
void GeminiProtocol::install()
|
||||
{
|
||||
Protocol::install(adopt_own(*new GeminiProtocol()));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <RequestServer/Protocol.h>
|
||||
|
||||
namespace RequestServer {
|
||||
|
||||
class GeminiProtocol final : public Protocol {
|
||||
public:
|
||||
virtual ~GeminiProtocol() override = default;
|
||||
|
||||
static void install();
|
||||
|
||||
private:
|
||||
GeminiProtocol();
|
||||
|
||||
virtual OwnPtr<Request> start_request(i32, ConnectionFromClient&, ByteString const& method, const URL::URL&, HashMap<ByteString, ByteString> const&, ReadonlyBytes body, Core::ProxyData proxy_data = {}) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "ConnectionCache.h"
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibGemini/GeminiResponse.h>
|
||||
#include <LibGemini/Job.h>
|
||||
#include <RequestServer/GeminiRequest.h>
|
||||
|
||||
namespace RequestServer {
|
||||
|
||||
GeminiRequest::GeminiRequest(ConnectionFromClient& client, NonnullRefPtr<Gemini::Job> job, NonnullOwnPtr<Core::File>&& output_stream, i32 request_id)
|
||||
: Request(client, move(output_stream), request_id)
|
||||
, m_job(move(job))
|
||||
{
|
||||
m_job->on_finish = [this](bool success) {
|
||||
Core::deferred_invoke([url = m_job->url(), socket = m_job->socket()] {
|
||||
ConnectionCache::request_did_finish(url, socket);
|
||||
});
|
||||
if (auto* response = m_job->response()) {
|
||||
set_downloaded_size(MUST(m_job->response_length()));
|
||||
if (!response->meta().is_empty()) {
|
||||
HashMap<ByteString, ByteString, CaseInsensitiveStringTraits> headers;
|
||||
headers.set("meta", response->meta());
|
||||
// Note: We're setting content-type to meta only on status==SUCCESS
|
||||
// we should perhaps have a better mechanism for this, since we
|
||||
// are already shoehorning the concept of "headers" here
|
||||
if (response->status() >= 20 && response->status() < 30) {
|
||||
headers.set("content-type", response->meta());
|
||||
}
|
||||
set_response_headers(headers);
|
||||
}
|
||||
}
|
||||
|
||||
// signal 100% request progress so any listeners can react
|
||||
// appropriately
|
||||
did_progress(downloaded_size(), downloaded_size());
|
||||
|
||||
did_finish(success);
|
||||
};
|
||||
m_job->on_progress = [this](Optional<u64> total, u64 current) {
|
||||
did_progress(move(total), current);
|
||||
};
|
||||
}
|
||||
|
||||
void GeminiRequest::set_certificate(ByteString, ByteString)
|
||||
{
|
||||
}
|
||||
|
||||
GeminiRequest::~GeminiRequest()
|
||||
{
|
||||
m_job->on_finish = nullptr;
|
||||
m_job->on_progress = nullptr;
|
||||
m_job->cancel();
|
||||
}
|
||||
|
||||
NonnullOwnPtr<GeminiRequest> GeminiRequest::create_with_job(Badge<GeminiProtocol>, ConnectionFromClient& client, NonnullRefPtr<Gemini::Job> job, NonnullOwnPtr<Core::File>&& output_stream, i32 request_id)
|
||||
{
|
||||
return adopt_own(*new GeminiRequest(client, move(job), move(output_stream), request_id));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibGemini/Forward.h>
|
||||
#include <RequestServer/Request.h>
|
||||
|
||||
namespace RequestServer {
|
||||
|
||||
class GeminiRequest final : public Request {
|
||||
public:
|
||||
virtual ~GeminiRequest() override;
|
||||
static NonnullOwnPtr<GeminiRequest> create_with_job(Badge<GeminiProtocol>, ConnectionFromClient&, NonnullRefPtr<Gemini::Job>, NonnullOwnPtr<Core::File>&&, i32 request_id);
|
||||
|
||||
Gemini::Job const& job() const { return *m_job; }
|
||||
|
||||
virtual URL::URL url() const override { return m_job->url(); }
|
||||
|
||||
private:
|
||||
explicit GeminiRequest(ConnectionFromClient&, NonnullRefPtr<Gemini::Job>, NonnullOwnPtr<Core::File>&&, i32 request_id);
|
||||
|
||||
virtual void set_certificate(ByteString certificate, ByteString key) override;
|
||||
|
||||
NonnullRefPtr<Gemini::Job> m_job;
|
||||
};
|
||||
|
||||
}
|
|
@ -12,7 +12,6 @@
|
|||
#include <LibMain/Main.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <RequestServer/ConnectionFromClient.h>
|
||||
#include <RequestServer/GeminiProtocol.h>
|
||||
#include <RequestServer/HttpProtocol.h>
|
||||
#include <RequestServer/HttpsProtocol.h>
|
||||
#include <signal.h>
|
||||
|
@ -46,7 +45,6 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
TRY(Core::System::unveil("/home/anon", "rwc"));
|
||||
TRY(Core::System::unveil(nullptr, nullptr));
|
||||
|
||||
RequestServer::GeminiProtocol::install();
|
||||
RequestServer::HttpProtocol::install();
|
||||
RequestServer::HttpsProtocol::install();
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ target_link_libraries(abench PRIVATE LibAudio LibFileSystem)
|
|||
target_link_libraries(aconv PRIVATE LibAudio LibFileSystem)
|
||||
target_link_libraries(animation PRIVATE LibGfx)
|
||||
target_link_libraries(gzip PRIVATE LibCompress)
|
||||
target_link_libraries(headless-browser PRIVATE LibCrypto LibFileSystem LibGemini LibGfx LibHTTP LibImageDecoderClient LibTLS LibWeb LibWebView LibWebSocket LibIPC LibJS LibDiff LibURL)
|
||||
target_link_libraries(headless-browser PRIVATE LibCrypto LibFileSystem LibGfx LibHTTP LibImageDecoderClient LibTLS LibWeb LibWebView LibWebSocket LibIPC LibJS LibDiff LibURL)
|
||||
target_link_libraries(icc PRIVATE LibGfx LibVideo LibURL)
|
||||
target_link_libraries(image PRIVATE LibGfx)
|
||||
target_link_libraries(isobmff PRIVATE LibGfx)
|
||||
|
|
Loading…
Reference in a new issue