1 /* HTTP response codes */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE /* Needed for asprintf() */
5 #endif
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "elinks.h"
12
13 #include "cache/cache.h"
14 #include "intl/gettext/libintl.h"
15 #include "network/connection.h"
16 #include "protocol/http/codes.h"
17 #include "protocol/uri.h"
18 #include "session/session.h"
19 #include "session/task.h"
20 #include "terminal/terminal.h"
21 #include "terminal/window.h"
22 #include "util/snprintf.h"
23 #include "viewer/text/draw.h"
24
25
26 struct http_code {
27 int num;
28 unsigned char *str;
29 };
30
31 /* Source: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html */
32 static struct http_code http_code[] = {
33 { 100, "Continue" },
34 { 101, "Switching Protocols" },
35 { 200, "OK" },
36 { 201, "Created" },
37 { 202, "Accepted" },
38 { 203, "Non-Authoritative Information" },
39 { 204, "No Content" },
40 { 205, "Reset Content" },
41 { 206, "Partial Content" },
42 { 300, "Multiple Choices" },
43 { 301, "Moved Permanently" },
44 { 302, "Found" },
45 { 303, "See Other" },
46 { 304, "Not Modified" },
47 { 305, "Use Proxy" },
48 { 306, "(Unused)" },
49 { 307, "Temporary Redirect" },
50 { 400, "Bad Request" },
51 { 401, "Unauthorized" },
52 { 402, "Payment Required" },
53 { 403, "Forbidden" },
54 { 404, "Not Found" },
55 { 405, "Method Not Allowed" },
56 { 406, "Not Acceptable" },
57 { 407, "Proxy Authentication Required" },
58 { 408, "Request Timeout" },
59 { 409, "Conflict" },
60 { 410, "Gone" },
61 { 411, "Length Required" },
62 { 412, "Precondition Failed" },
63 { 413, "Request Entity Too Large" },
64 { 414, "Request-URI Too Long" },
65 { 415, "Unsupported Media Type" },
66 { 416, "Requested Range Not Satisfiable" },
67 { 417, "Expectation Failed" },
68 { 500, "Internal Server Error" },
69 { 501, "Not Implemented" },
70 { 502, "Bad Gateway" },
71 { 503, "Service Unavailable" },
72 { 504, "Gateway Timeout" },
73 { 505, "HTTP Version Not Supported" },
74 };
75
76 static int
compare_http_codes(const void * key,const void * element)77 compare_http_codes(const void *key, const void *element)
78 {
79 int first = (long) key;
80 int second = ((struct http_code *) element)->num;
81
82 return first - second;
83 }
84
85 static unsigned char *
http_code_to_string(int code)86 http_code_to_string(int code)
87 {
88 struct http_code *element = bsearch((void *) (long) code, http_code,
89 sizeof_array(http_code),
90 sizeof(*element),
91 compare_http_codes);
92
93 if (element) return element->str;
94
95 return NULL;
96 }
97
98
99 /* TODO: Some short intermediate document for the 3xx messages? --pasky */
100 static unsigned char *
get_http_error_document(struct terminal * term,struct uri * uri,int code)101 get_http_error_document(struct terminal *term, struct uri *uri, int code)
102 {
103 unsigned char *codestr = http_code_to_string(code);
104 unsigned char *title = asprintfa(_("HTTP error %03d", term), code);
105 struct string string;
106
107 if (!codestr) codestr = "Unknown error";
108
109 if (!init_string(&string)) {
110 mem_free_if(title);
111 return NULL;
112 }
113
114 add_format_to_string(&string,
115 "<html>\n"
116 " <head><title>%s</title></head>\n"
117 " <body>\n"
118 " <h1 align=\"left\">%s: %s</h1>\n"
119 #ifndef CONFIG_SMALL
120 " <hr />\n"
121 " <p>\n"
122 #endif
123 , title, title, codestr);
124
125 #ifndef CONFIG_SMALL
126 add_format_to_string(&string, _(
127 " An error occurred on the server while fetching the document you\n"
128 " requested. However, the server did not send back any explanation of what\n"
129 " happenned, so it is unknown what went wrong. Please contact the web\n"
130 " server administrator about this, if you believe that this error should\n"
131 " not occur since it is not a nice behaviour from the web server at all\n"
132 " and indicates that there is some much deeper problem with the web server\n"
133 " software.\n",
134 term));
135
136 add_format_to_string(&string,
137 " </p>\n"
138 " <p>\n"
139 " URI: <a href=\"%s\">%s</a>\n", struri(uri), struri(uri));
140 #endif
141 add_format_to_string(&string,
142 #ifndef CONFIG_SMALL
143 " </p>\n"
144 " <hr />\n"
145 #endif
146 " </body>\n"
147 "</html>\n");
148
149 mem_free_if(title);
150
151 return string.source;
152 }
153
154 struct http_error_info {
155 int code;
156 struct uri *uri;
157 };
158
159 static void
show_http_error_document(struct session * ses,void * data)160 show_http_error_document(struct session *ses, void *data)
161 {
162 struct http_error_info *info = data;
163 struct terminal *term = ses->tab->term;
164 struct cache_entry *cached = find_in_cache(info->uri);
165 struct cache_entry *cache = cached ? cached : get_cache_entry(info->uri);
166 unsigned char *str = NULL;
167
168 if (cache) str = get_http_error_document(term, info->uri, info->code);
169
170 if (str) {
171 if (cached) delete_entry_content(cache);
172 mem_free_set(&cache->content_type, stracpy("text/html"));
173 add_fragment(cache, 0, str, strlen(str));
174 mem_free(str);
175
176 draw_formatted(ses, 1);
177 }
178
179 done_uri(info->uri);
180 mem_free(info);
181 }
182
183
184 void
http_error_document(struct connection * conn,int code)185 http_error_document(struct connection *conn, int code)
186 {
187 struct http_error_info *info;
188
189 assert(conn && conn->uri);
190
191 info = mem_calloc(1, sizeof(*info));
192 if (!info) return;
193
194 info->code = code;
195 info->uri = get_uri_reference(conn->uri);
196
197 add_questions_entry(show_http_error_document, info);
198 }
199