2 * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/socket.h>
31 generate_meta(int status_code, char *meta_response_string, const char *mime)
35 snprintf(meta_response_string, 1024, "%d Present input\r\n", status_code);
37 case STATUS_SENSITIVE_INPUT:
38 snprintf(meta_response_string, 1024, "%d Present sensitive input\r\n",
43 /* Could not deducte mime type, so send text/gemini as default */
44 snprintf(meta_response_string, 1024, "%d text/gemini\r\n", status_code);
46 snprintf(meta_response_string, 1024, "%d %s\r\n", status_code, mime);
48 case STATUS_REDIRECT_TEMP:
49 snprintf(meta_response_string, 1024, "%d Temporary redirect\r\n",
52 case STATUS_REDIRECT_PERM:
53 snprintf(meta_response_string, 1024, "%d Permanent redirect\r\n",
56 case STATUS_TEMP_UNAVAILABLE:
57 snprintf(meta_response_string, 1024, "%d Temporary failure\r\n",
60 case STATUS_SERVER_UNAVAILABLE:
61 snprintf(meta_response_string, 1024, "%d Server unavailable\r\n",
64 case STATUS_CGI_ERROR:
65 snprintf(meta_response_string, 1024, "%d CGI Error\r\n", status_code);
67 case STATUS_PROXY_ERROR:
68 snprintf(meta_response_string, 1024, "%d Proxy error\r\n", status_code);
70 case STATUS_SLOW_DOWN:
71 snprintf(meta_response_string, 1024, "%d Slow down\r\n", status_code);
73 case STATUS_PERM_FAILURE:
74 snprintf(meta_response_string, 1024, "%d Permanent failure\r\n", status_code);
76 case STATUS_NOT_FOUND:
77 snprintf(meta_response_string, 1024, "%d Resource not found\r\n",
81 snprintf(meta_response_string, 1024, "%d Resource is gone\r\n", status_code);
83 case STATUS_PROXY_REQUEST_REFUSED:
84 snprintf(meta_response_string, 1024, "%d Proxy request refused\r\n",
87 case STATUS_BAD_REQUEST:
88 snprintf(meta_response_string, 1024, "%d Bad Request\r\n", status_code);
90 case STATUS_CLIENT_CERT_REQUIRED:
91 snprintf(meta_response_string, 1024, "%d Client Certificate Required\r\n",
94 case STATUS_CERT_NOT_AUTHORIZED:
95 snprintf(meta_response_string, 1024, "%d Certificate not authorized\r\n",
98 case STATUS_CERT_NOT_VALID:
99 snprintf(meta_response_string, 1024, "%d Certificate not valid\r\n",
103 snprintf(meta_response_string, 1024, "%d Unkown status code\r\n",
110 send_non_success_response(SSL *ssl_peer, int status_code)
114 memset(meta, 0, sizeof(meta));
116 generate_meta(status_code, meta, NULL);
118 log_debug("Send non success response to client: %d", status_code);
120 if (SSL_write(ssl_peer, meta, strlen(meta)) <= 0) {
121 log_warn("Could not send response to client");
129 send_response(SSL *ssl_peer, int status_code, const char *gemini_file_path,
136 // <STATUS><SPACE><META><CR><LF>
138 memset(meta, 0, sizeof(meta));
139 memset(buffer, 0, sizeof(buffer));
141 generate_meta(status_code, meta, mime);
143 if (SSL_write(ssl_peer, meta, strlen(meta)) <= 0) {
144 log_warn("Could not send response to client");
148 /* Close connection and do not send a response if status code is not
151 if (status_code < 30 && status_code >= 20) {
152 fd = open(gemini_file_path, O_RDONLY);
154 log_warn("Cannot open requested file");
158 while ((len = read(fd, buffer, sizeof(buffer)-1)) > 0) {
159 if (SSL_write(ssl_peer, buffer, len) <= 0) {
160 log_warn("Could not send response to client");
173 check_gemini_file(const char *gemini_file_path)
177 if (stat(gemini_file_path, &sb) == -1) {
178 log_warn("Cannot open requested file");
182 if ((sb.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
183 log_warn("Cannot read requested file");
187 if ((sb.st_mode & S_IFMT) == S_IFDIR)