Skip to content

Commit 308a755

Browse files
deoxxaawesomekling
authored andcommitted
LibGemini: Implement basic Gemini protocol support
1 parent 656d1e1 commit 308a755

11 files changed

Lines changed: 704 additions & 0 deletions

File tree

‎Libraries/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_subdirectory(LibCore)
44
add_subdirectory(LibCrypto)
55
add_subdirectory(LibDebug)
66
add_subdirectory(LibDesktop)
7+
add_subdirectory(LibGemini)
78
add_subdirectory(LibGfx)
89
add_subdirectory(LibGUI)
910
add_subdirectory(LibHTTP)

‎Libraries/LibGemini/CMakeLists.txt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
set(SOURCES
2+
GeminiJob.cpp
3+
GeminiRequest.cpp
4+
GeminiResponse.cpp
5+
Job.cpp
6+
)
7+
8+
serenity_lib(LibGemini gemini)
9+
target_link_libraries(LibGemini LibCore LibTLS)

‎Libraries/LibGemini/Forward.h‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2020, The SerenityOS developers.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
namespace Gemini {
28+
29+
class GeminiRequest;
30+
class GeminiResponse;
31+
class GeminiJob;
32+
class Job;
33+
34+
}

‎Libraries/LibGemini/GeminiJob.cpp‎

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2020, The SerenityOS developers.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include <LibCore/EventLoop.h>
28+
#include <LibGemini/GeminiJob.h>
29+
#include <LibGemini/GeminiResponse.h>
30+
#include <LibTLS/TLSv12.h>
31+
#include <stdio.h>
32+
#include <unistd.h>
33+
34+
//#define GEMINIJOB_DEBUG
35+
36+
namespace Gemini {
37+
38+
void GeminiJob::start()
39+
{
40+
ASSERT(!m_socket);
41+
m_socket = TLS::TLSv12::construct(this);
42+
m_socket->on_tls_connected = [this] {
43+
#ifdef GEMINIJOB_DEBUG
44+
dbg() << "GeminiJob: on_connected callback";
45+
#endif
46+
on_socket_connected();
47+
};
48+
m_socket->on_tls_error = [this](TLS::AlertDescription error) {
49+
if (error == TLS::AlertDescription::HandshakeFailure) {
50+
deferred_invoke([this](auto&) {
51+
return did_fail(Core::NetworkJob::Error::ProtocolFailed);
52+
});
53+
} else if (error == TLS::AlertDescription::DecryptError) {
54+
deferred_invoke([this](auto&) {
55+
return did_fail(Core::NetworkJob::Error::ConnectionFailed);
56+
});
57+
} else {
58+
deferred_invoke([this](auto&) {
59+
return did_fail(Core::NetworkJob::Error::TransmissionFailed);
60+
});
61+
}
62+
};
63+
m_socket->on_tls_finished = [this] {
64+
finish_up();
65+
};
66+
bool success = ((TLS::TLSv12&)*m_socket).connect(m_request.url().host(), m_request.url().port());
67+
if (!success) {
68+
deferred_invoke([this](auto&) {
69+
return did_fail(Core::NetworkJob::Error::ConnectionFailed);
70+
});
71+
}
72+
}
73+
74+
void GeminiJob::shutdown()
75+
{
76+
if (!m_socket)
77+
return;
78+
m_socket->on_tls_ready_to_read = nullptr;
79+
m_socket->on_tls_connected = nullptr;
80+
remove_child(*m_socket);
81+
m_socket = nullptr;
82+
}
83+
84+
void GeminiJob::read_while_data_available(Function<IterationDecision()> read)
85+
{
86+
while (m_socket->can_read()) {
87+
if (read() == IterationDecision::Break)
88+
break;
89+
}
90+
}
91+
92+
void GeminiJob::register_on_ready_to_read(Function<void()> callback)
93+
{
94+
m_socket->on_tls_ready_to_read = [callback = move(callback)](auto&) {
95+
callback();
96+
};
97+
}
98+
99+
void GeminiJob::register_on_ready_to_write(Function<void()> callback)
100+
{
101+
m_socket->on_tls_ready_to_write = [callback = move(callback)](auto&) {
102+
callback();
103+
};
104+
}
105+
106+
bool GeminiJob::can_read_line() const
107+
{
108+
return m_socket->can_read_line();
109+
}
110+
111+
ByteBuffer GeminiJob::read_line(size_t size)
112+
{
113+
return m_socket->read_line(size);
114+
}
115+
116+
ByteBuffer GeminiJob::receive(size_t size)
117+
{
118+
return m_socket->read(size);
119+
}
120+
121+
bool GeminiJob::can_read() const
122+
{
123+
return m_socket->can_read();
124+
}
125+
126+
bool GeminiJob::eof() const
127+
{
128+
return m_socket->eof();
129+
}
130+
131+
bool GeminiJob::write(const ByteBuffer& data)
132+
{
133+
return m_socket->write(data);
134+
}
135+
136+
}

‎Libraries/LibGemini/GeminiJob.h‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2020, The SerenityOS developers.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#pragma once
28+
29+
#include <LibCore/NetworkJob.h>
30+
#include <LibGemini/GeminiRequest.h>
31+
#include <LibGemini/GeminiResponse.h>
32+
#include <LibGemini/Job.h>
33+
#include <LibTLS/TLSv12.h>
34+
35+
namespace Gemini {
36+
37+
class GeminiJob final : public Job {
38+
C_OBJECT(GeminiJob)
39+
public:
40+
explicit GeminiJob(const GeminiRequest& request)
41+
: Job(request)
42+
{
43+
}
44+
45+
virtual ~GeminiJob() override
46+
{
47+
}
48+
49+
virtual void start() override;
50+
virtual void shutdown() override;
51+
52+
protected:
53+
virtual void register_on_ready_to_read(Function<void()>) override;
54+
virtual void register_on_ready_to_write(Function<void()>) override;
55+
virtual bool can_read_line() const override;
56+
virtual ByteBuffer read_line(size_t) override;
57+
virtual bool can_read() const override;
58+
virtual ByteBuffer receive(size_t) override;
59+
virtual bool eof() const override;
60+
virtual bool write(const ByteBuffer&) override;
61+
virtual bool is_established() const override { return m_socket->is_established(); }
62+
virtual bool should_fail_on_empty_payload() const override { return false; }
63+
virtual void read_while_data_available(Function<IterationDecision()>) override;
64+
65+
private:
66+
RefPtr<TLS::TLSv12> m_socket;
67+
bool m_queued_finish { false };
68+
};
69+
70+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2020, The SerenityOS developers.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include <AK/StringBuilder.h>
28+
#include <AK/URL.h>
29+
#include <LibGemini/GeminiJob.h>
30+
#include <LibGemini/GeminiRequest.h>
31+
32+
namespace Gemini {
33+
34+
GeminiRequest::GeminiRequest()
35+
{
36+
}
37+
38+
GeminiRequest::~GeminiRequest()
39+
{
40+
}
41+
42+
RefPtr<Core::NetworkJob> GeminiRequest::schedule()
43+
{
44+
auto job = GeminiJob::construct(*this);
45+
job->start();
46+
return job;
47+
}
48+
49+
ByteBuffer GeminiRequest::to_raw_request() const
50+
{
51+
StringBuilder builder;
52+
builder.append(m_url.to_string());
53+
builder.append("\r\n");
54+
return builder.to_byte_buffer();
55+
}
56+
57+
Optional<GeminiRequest> GeminiRequest::from_raw_request(const ByteBuffer& raw_request)
58+
{
59+
URL url = StringView(raw_request);
60+
if (!url.is_valid())
61+
return {};
62+
GeminiRequest request;
63+
request.m_url = url;
64+
return request;
65+
}
66+
67+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2020, The SerenityOS developers.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#pragma once
28+
29+
#include <AK/Optional.h>
30+
#include <AK/String.h>
31+
#include <AK/URL.h>
32+
#include <LibCore/Forward.h>
33+
34+
namespace Gemini {
35+
36+
class GeminiRequest {
37+
public:
38+
GeminiRequest();
39+
~GeminiRequest();
40+
41+
const URL& url() const { return m_url; }
42+
void set_url(const URL& url) { m_url = url; }
43+
44+
ByteBuffer to_raw_request() const;
45+
46+
RefPtr<Core::NetworkJob> schedule();
47+
48+
static Optional<GeminiRequest> from_raw_request(const ByteBuffer&);
49+
50+
private:
51+
URL m_url;
52+
};
53+
54+
}

0 commit comments

Comments
 (0)