aboutsummaryrefslogtreecommitdiff
path: root/maple/titan.cc
blob: 2021903148a3a885b2934cae16705d51aa82fa66 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * This file is part of Maple <https://github.com/gemrest/maple>.
 * Copyright (C) 2022-2022 Fuwn <[email protected]>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2022-2022 Fuwn <[email protected]>
 * SPDX-License-Identifier: GPL-3.0-only
 */

#include <cstddef>
#include <fstream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

#include "titan.hh"

namespace maple::titan {
auto parameters_to_map(const std::vector<std::string> &parameters)
    -> std::map<std::string, std::string> {
  std::map<std::string, std::string> parameters_map;

  for (const auto &parameter : parameters) {
    // Find the key in `parameter`
    const std::size_t parameter_delimiter_position = parameter.find('=');

    if (parameter_delimiter_position == std::string::npos) {
      continue;
    }

    const std::string key = parameter.substr(0, parameter_delimiter_position);
    const std::string value =
        parameter.substr(parameter_delimiter_position + 1);

    // Add the key and value to `parameters_map`
    parameters_map.emplace(key, value);
  }

  return parameters_map;
}

auto handle_client(std::stringstream &response, std::string path,
                   const std::string &titan_token, std::size_t titan_max_size)
    -> void {
  std::vector<std::string> parameters;
  // Find path in `path`
  std::size_t delimiter_position = path.find(';');
  std::string update_path = path.substr(0, delimiter_position);
  const std::string body = path.substr(path.find('\n') + 1, path.length() - 1);

  path.erase(path.find('\n') - 1, path.length() - 1);
  // parameters.push_back(update_path);
  path.erase(0, delimiter_position + 1); // Remove path from `path`

  // Find mime parameter in `path`
  delimiter_position = path.find(';');

  parameters.push_back(path.substr(0, delimiter_position));
  path.erase(0, delimiter_position + 1); // Remove mime parameter from `path`

  // Find size parameter in `path`
  delimiter_position = path.find(';');

  parameters.push_back(path.substr(0, delimiter_position));

  // Find token parameter in `path`
  delimiter_position = path.find(';');

  // Since the token is optional, only get and assign the token
  // parameters value if it exists.
  if (delimiter_position != std::string::npos) {
    parameters.push_back(
        path.substr(delimiter_position + 1, path.length() - 1));
  }

  /// Check if a parameter exists within a `std::vector` of Titan
  /// parameters.
  /* auto parameter_exists = [](
    const std::vector<std::string> &_parameters,
    const std::string &parameter
  ) -> bool {
    return std::any_of(
      _parameters.begin(),
      _parameters.end(),
      [&](const std::string &s) -> bool {
        return s.find(parameter) != std::string::npos;
      }
    );
  }; */

  std::map<std::string, std::string> parameters_map =
      maple::titan::parameters_to_map(parameters);

  // Make sure all tokens have been supplied
  for (;;) {
    if (parameters_map.find("mime") == parameters_map.end()) {
      response << "20 text/gemini\r\nThe serve (Maple) did not "
                  "receive a mime parameter!";
      break;
    }

    if (parameters_map.find("size") == parameters_map.end()) {
      response << "20 text/gemini\r\nThe serve (Maple) did not "
                  "receive a size parameter!";

      break;
    }

    if (!titan_token.empty() &&
        parameters_map.find("token") == parameters_map.end()) {
      response << "20 text/gemini\r\nThe serve (Maple) did not "
                  "receive a token parameter!";

      break;
    }

    try {
      const std::size_t body_size =
          static_cast<std::size_t>(std::stoi(parameters_map.at("size")));

      if (body_size > titan_max_size) {
        response << "20 text/gemini\r\nThe server (Maple) received a body "
                 << "which is larger than the maximum allowed body size ("
                 << titan_max_size << ").";

        break;
      }
    } catch (...) {
      response << "20 text/gemini\r\nThe server (Maple) could not interpret "
                  "the size parameter as an integer!";

      break;
    }

    if (update_path == "/") {
      update_path = "/index.gmi";
    }

    const auto token_iterator = parameters_map.find("token");
    const std::string token =
        token_iterator == parameters_map.end() ? "" : token_iterator->second;

    if (token == titan_token) {
      std::ofstream file(".maple/gmi" + update_path);

      file << body;

      response << "20 text/gemini\r\nSuccessfully wrote " << body.length()
               << " bytes to " << update_path << '!';
    } else {
      response << "20 text/gemini\r\nThe server (Maple) wrote to "
               << update_path;
    }

    break;
  }
}
} // namespace maple::titan