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