6 #include "stat_cache.h"
9 #include "configfile.h"
13 #include <sys/types.h>
28 #include "sys-socket.h"
30 int http_response_write_header(server
*srv
, connection
*con
) {
38 if (con
->request
.http_version
== HTTP_VERSION_1_1
) {
39 buffer_copy_string_len(b
, CONST_STR_LEN("HTTP/1.1 "));
41 buffer_copy_string_len(b
, CONST_STR_LEN("HTTP/1.0 "));
43 buffer_append_int(b
, con
->http_status
);
44 buffer_append_string_len(b
, CONST_STR_LEN(" "));
45 buffer_append_string(b
, get_http_status_name(con
->http_status
));
47 /* disable keep-alive if requested */
48 if (con
->request_count
> con
->conf
.max_keep_alive_requests
|| 0 == con
->conf
.max_keep_alive_idle
) {
51 con
->keep_alive_idle
= con
->conf
.max_keep_alive_idle
;
54 if (con
->request
.http_version
!= HTTP_VERSION_1_1
|| con
->keep_alive
== 0) {
55 if (con
->keep_alive
) {
56 response_header_overwrite(srv
, con
, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
58 response_header_overwrite(srv
, con
, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
62 if (con
->response
.transfer_encoding
& HTTP_TRANSFER_ENCODING_CHUNKED
) {
63 response_header_overwrite(srv
, con
, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
68 for (i
= 0; i
< con
->response
.headers
->used
; i
++) {
71 ds
= (data_string
*)con
->response
.headers
->data
[i
];
73 if (!buffer_is_empty(ds
->value
) && !buffer_is_empty(ds
->key
) &&
74 0 != strncasecmp(ds
->key
->ptr
, CONST_STR_LEN("X-LIGHTTPD-")) &&
75 0 != strncasecmp(ds
->key
->ptr
, CONST_STR_LEN("X-Sendfile"))) {
76 if (0 == strcasecmp(ds
->key
->ptr
, "Date")) have_date
= 1;
77 if (0 == strcasecmp(ds
->key
->ptr
, "Server")) have_server
= 1;
78 if (0 == strcasecmp(ds
->key
->ptr
, "Content-Encoding") && 304 == con
->http_status
) continue;
80 buffer_append_string_len(b
, CONST_STR_LEN("\r\n"));
81 buffer_append_string_buffer(b
, ds
->key
);
82 buffer_append_string_len(b
, CONST_STR_LEN(": "));
85 * the value might contain newlines, encode them with at least one white-space
87 buffer_append_string_encoded(b
, CONST_BUF_LEN(ds
->value
), ENCODING_HTTP_HEADER
);
89 buffer_append_string_buffer(b
, ds
->value
);
95 /* HTTP/1.1 requires a Date: header */
96 buffer_append_string_len(b
, CONST_STR_LEN("\r\nDate: "));
98 /* cache the generated timestamp */
99 if (srv
->cur_ts
!= srv
->last_generated_date_ts
) {
100 buffer_string_prepare_copy(srv
->ts_date_str
, 255);
102 buffer_append_strftime(srv
->ts_date_str
, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv
->cur_ts
)));
104 srv
->last_generated_date_ts
= srv
->cur_ts
;
107 buffer_append_string_buffer(b
, srv
->ts_date_str
);
111 if (!buffer_string_is_empty(con
->conf
.server_tag
)) {
112 buffer_append_string_len(b
, CONST_STR_LEN("\r\nServer: "));
113 buffer_append_string_encoded(b
, CONST_BUF_LEN(con
->conf
.server_tag
), ENCODING_HTTP_HEADER
);
117 buffer_append_string_len(b
, CONST_STR_LEN("\r\n\r\n"));
119 con
->bytes_header
= buffer_string_length(b
);
121 if (con
->conf
.log_response_header
) {
122 log_error_write(srv
, __FILE__
, __LINE__
, "sSb", "Response-Header:", "\n", b
);
125 chunkqueue_prepend_buffer(con
->write_queue
, b
);
132 #include <openssl/bn.h>
133 #include <openssl/err.h>
134 static void https_add_ssl_client_entries(server
*srv
, connection
*con
) {
139 long vr
= SSL_get_verify_result(con
->ssl
);
140 if (vr
!= X509_V_OK
) {
142 ERR_error_string_n(vr
, errstr
, sizeof(errstr
));
143 buffer_copy_string_len(srv
->tmp_buf
, CONST_STR_LEN("FAILED:"));
144 buffer_append_string(srv
->tmp_buf
, errstr
);
145 array_set_key_value(con
->environment
,
146 CONST_STR_LEN("SSL_CLIENT_VERIFY"),
147 CONST_BUF_LEN(srv
->tmp_buf
));
149 } else if (!(xs
= SSL_get_peer_certificate(con
->ssl
))) {
150 array_set_key_value(con
->environment
,
151 CONST_STR_LEN("SSL_CLIENT_VERIFY"),
152 CONST_STR_LEN("NONE"));
155 array_set_key_value(con
->environment
,
156 CONST_STR_LEN("SSL_CLIENT_VERIFY"),
157 CONST_STR_LEN("SUCCESS"));
160 buffer_copy_string_len(srv
->tmp_buf
, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
161 xn
= X509_get_subject_name(xs
);
162 for (i
= 0, nentries
= X509_NAME_entry_count(xn
); i
< nentries
; ++i
) {
167 if (!(xe
= X509_NAME_get_entry(xn
, i
))) {
170 xobjnid
= OBJ_obj2nid((ASN1_OBJECT
*)X509_NAME_ENTRY_get_object(xe
));
171 xobjsn
= OBJ_nid2sn(xobjnid
);
173 buffer_string_set_length(srv
->tmp_buf
, sizeof("SSL_CLIENT_S_DN_")-1);
174 buffer_append_string(srv
->tmp_buf
, xobjsn
);
175 array_set_key_value(con
->environment
,
176 CONST_BUF_LEN(srv
->tmp_buf
),
177 (const char *)X509_NAME_ENTRY_get_data(xe
)->data
,
178 X509_NAME_ENTRY_get_data(xe
)->length
);
183 ASN1_INTEGER
*xsn
= X509_get_serialNumber(xs
);
184 BIGNUM
*serialBN
= ASN1_INTEGER_to_BN(xsn
, NULL
);
185 char *serialHex
= BN_bn2hex(serialBN
);
186 array_set_key_value(con
->environment
,
187 CONST_STR_LEN("SSL_CLIENT_M_SERIAL"),
188 serialHex
, strlen(serialHex
));
189 OPENSSL_free(serialHex
);
193 if (!buffer_string_is_empty(con
->conf
.ssl_verifyclient_username
)) {
194 /* pick one of the exported values as "REMOTE_USER", for example
195 * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" or "SSL_CLIENT_S_DN_emailAddress"
197 data_string
*ds
= (data_string
*)array_get_element(con
->environment
, con
->conf
.ssl_verifyclient_username
->ptr
);
198 if (ds
) array_set_key_value(con
->environment
, CONST_STR_LEN("REMOTE_USER"), CONST_BUF_LEN(ds
->value
));
201 if (con
->conf
.ssl_verifyclient_export_cert
) {
203 if (NULL
!= (bio
= BIO_new(BIO_s_mem()))) {
207 PEM_write_bio_X509(bio
, xs
);
208 n
= BIO_pending(bio
);
210 if (NULL
== (envds
= (data_string
*)array_get_unused_element(con
->environment
, TYPE_STRING
))) {
211 envds
= data_string_init();
214 buffer_copy_string_len(envds
->key
, CONST_STR_LEN("SSL_CLIENT_CERT"));
215 buffer_string_prepare_copy(envds
->value
, n
);
216 BIO_read(bio
, envds
->value
->ptr
, n
);
218 buffer_commit(envds
->value
, n
);
219 array_replace(con
->environment
, (data_unset
*)envds
);
227 handler_t
http_response_prepare(server
*srv
, connection
*con
) {
230 /* looks like someone has already done a decision */
231 if (con
->mode
== DIRECT
&&
232 (con
->http_status
!= 0 && con
->http_status
!= 200)) {
233 /* remove a packets in the queue */
234 if (con
->file_finished
== 0) {
235 chunkqueue_reset(con
->write_queue
);
238 return HANDLER_FINISHED
;
241 /* no decision yet, build conf->filename */
242 if (con
->mode
== DIRECT
&& buffer_is_empty(con
->physical
.path
)) {
245 /* we only come here when we have the parse the full request again
247 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
248 * problem here as mod_setenv might get called multiple times
250 * fastcgi-auth might lead to a COMEBACK too
251 * fastcgi again dead server too
253 * mod_compress might add headers twice too
257 config_cond_cache_reset(srv
, con
);
258 config_setup_connection(srv
, con
); /* Perhaps this could be removed at other places. */
260 if (con
->conf
.log_condition_handling
) {
261 log_error_write(srv
, __FILE__
, __LINE__
, "s", "run condition");
268 * - uri.path (secure)
274 * Name according to RFC 2396
281 * (scheme)://(authority)(path)?(query)#fragment
286 /* initial scheme value. can be overwritten for example by mod_extforward later */
287 if (con
->srv_socket
->is_ssl
) {
288 buffer_copy_string_len(con
->uri
.scheme
, CONST_STR_LEN("https"));
290 buffer_copy_string_len(con
->uri
.scheme
, CONST_STR_LEN("http"));
292 buffer_copy_buffer(con
->uri
.authority
, con
->request
.http_host
);
293 buffer_to_lower(con
->uri
.authority
);
295 /** their might be a fragment which has to be cut away */
296 if (NULL
!= (qstr
= strchr(con
->request
.uri
->ptr
, '#'))) {
297 buffer_string_set_length(con
->request
.uri
, qstr
- con
->request
.uri
->ptr
);
300 /** extract query string from request.uri */
301 if (NULL
!= (qstr
= strchr(con
->request
.uri
->ptr
, '?'))) {
302 buffer_copy_string (con
->uri
.query
, qstr
+ 1);
303 buffer_copy_string_len(con
->uri
.path_raw
, con
->request
.uri
->ptr
, qstr
- con
->request
.uri
->ptr
);
305 buffer_reset (con
->uri
.query
);
306 buffer_copy_buffer(con
->uri
.path_raw
, con
->request
.uri
);
309 /* decode url to path
311 * - decode url-encodings (e.g. %20 -> ' ')
312 * - remove path-modifiers (e.g. /../)
315 if (con
->request
.http_method
== HTTP_METHOD_OPTIONS
&&
316 con
->uri
.path_raw
->ptr
[0] == '*' && con
->uri
.path_raw
->ptr
[1] == '\0') {
318 buffer_copy_buffer(con
->uri
.path
, con
->uri
.path_raw
);
320 buffer_copy_buffer(srv
->tmp_buf
, con
->uri
.path_raw
);
321 buffer_urldecode_path(srv
->tmp_buf
);
322 buffer_path_simplify(con
->uri
.path
, srv
->tmp_buf
);
325 con
->conditional_is_valid
[COMP_SERVER_SOCKET
] = 1; /* SERVERsocket */
326 con
->conditional_is_valid
[COMP_HTTP_SCHEME
] = 1; /* Scheme: */
327 con
->conditional_is_valid
[COMP_HTTP_HOST
] = 1; /* Host: */
328 con
->conditional_is_valid
[COMP_HTTP_REMOTE_IP
] = 1; /* Client-IP */
329 con
->conditional_is_valid
[COMP_HTTP_REFERER
] = 1; /* Referer: */
330 con
->conditional_is_valid
[COMP_HTTP_USER_AGENT
] = /* User-Agent: */
331 con
->conditional_is_valid
[COMP_HTTP_LANGUAGE
] = 1; /* Accept-Language: */
332 con
->conditional_is_valid
[COMP_HTTP_COOKIE
] = 1; /* Cookie: */
333 con
->conditional_is_valid
[COMP_HTTP_REQUEST_METHOD
] = 1; /* REQUEST_METHOD */
334 con
->conditional_is_valid
[COMP_HTTP_URL
] = 1; /* HTTPurl */
335 con
->conditional_is_valid
[COMP_HTTP_QUERY_STRING
] = 1; /* HTTPqs */
336 config_patch_connection(srv
, con
);
339 if (con
->srv_socket
->is_ssl
&& con
->conf
.ssl_verifyclient
) {
340 https_add_ssl_client_entries(srv
, con
);
344 /* do we have to downgrade to 1.0 ? */
345 if (!con
->conf
.allow_http11
) {
346 con
->request
.http_version
= HTTP_VERSION_1_0
;
349 if (con
->conf
.log_request_handling
) {
350 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- splitting Request-URI");
351 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Request-URI : ", con
->request
.uri
);
352 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI-scheme : ", con
->uri
.scheme
);
353 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI-authority : ", con
->uri
.authority
);
354 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI-path (raw) : ", con
->uri
.path_raw
);
355 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI-path (clean): ", con
->uri
.path
);
356 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI-query : ", con
->uri
.query
);
359 /* con->conf.max_request_size is in kBytes */
360 if (0 != con
->conf
.max_request_size
&&
361 (off_t
)con
->request
.content_length
> ((off_t
)con
->conf
.max_request_size
<< 10)) {
362 log_error_write(srv
, __FILE__
, __LINE__
, "sos",
363 "request-size too long:", (off_t
) con
->request
.content_length
, "-> 413");
365 con
->http_status
= 413;
366 con
->file_finished
= 1;
368 return HANDLER_FINISHED
;
376 * - based on the raw URL
380 switch(r
= plugins_call_handle_uri_raw(srv
, con
)) {
383 case HANDLER_FINISHED
:
384 case HANDLER_COMEBACK
:
385 case HANDLER_WAIT_FOR_EVENT
:
389 log_error_write(srv
, __FILE__
, __LINE__
, "sd", "handle_uri_raw: unknown return value", r
);
397 * - based on the clean URL
401 switch(r
= plugins_call_handle_uri_clean(srv
, con
)) {
404 case HANDLER_FINISHED
:
405 case HANDLER_COMEBACK
:
406 case HANDLER_WAIT_FOR_EVENT
:
410 log_error_write(srv
, __FILE__
, __LINE__
, "");
414 if (con
->request
.http_method
== HTTP_METHOD_OPTIONS
&&
415 con
->uri
.path
->ptr
[0] == '*' && con
->uri
.path_raw
->ptr
[1] == '\0') {
416 /* option requests are handled directly without checking of the path */
418 response_header_insert(srv
, con
, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
420 con
->http_status
= 200;
421 con
->file_finished
= 1;
423 return HANDLER_FINISHED
;
430 * logical filename (URI) becomes a physical filename here
440 * ... ISREG() -> ok, go on
441 * ... ISDIR() -> index-file -> redirect
451 * SEARCH DOCUMENT ROOT
456 buffer_copy_buffer(con
->physical
.doc_root
, con
->conf
.document_root
);
457 buffer_copy_buffer(con
->physical
.rel_path
, con
->uri
.path
);
459 #if defined(__WIN32) || defined(__CYGWIN__)
460 /* strip dots from the end and spaces
462 * windows/dos handle those filenames as the same file
464 * foo == foo. == foo..... == "foo... " == "foo.. ./"
466 * This will affect in some cases PATHINFO
468 * on native windows we could prepend the filename with \\?\ to circumvent
469 * this behaviour. I have no idea how to push this through cygwin
473 if (con
->physical
.rel_path
->used
> 1) {
474 buffer
*b
= con
->physical
.rel_path
;
475 size_t len
= buffer_string_length(b
);
477 /* strip trailing " /" or "./" once */
479 b
->ptr
[len
- 1] == '/' &&
480 (b
->ptr
[len
- 2] == ' ' || b
->ptr
[len
- 2] == '.')) {
483 /* strip all trailing " " and "." */
484 while (len
> 0 && ( ' ' == b
->ptr
[len
-1] || '.' == b
->ptr
[len
-1] ) ) --len
;
485 buffer_string_set_length(b
, len
);
489 if (con
->conf
.log_request_handling
) {
490 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- before doc_root");
491 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Doc-Root :", con
->physical
.doc_root
);
492 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Rel-Path :", con
->physical
.rel_path
);
493 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
495 /* the docroot plugin should set the doc_root and might also set the physical.path
496 * for us (all vhost-plugins are supposed to set the doc_root)
498 switch(r
= plugins_call_handle_docroot(srv
, con
)) {
501 case HANDLER_FINISHED
:
502 case HANDLER_COMEBACK
:
503 case HANDLER_WAIT_FOR_EVENT
:
507 log_error_write(srv
, __FILE__
, __LINE__
, "");
511 /* MacOS X and Windows can't distiguish between upper and lower-case
513 * convert to lower-case
515 if (con
->conf
.force_lowercase_filenames
) {
516 buffer_to_lower(con
->physical
.rel_path
);
519 /* the docroot plugins might set the servername, if they don't we take http-host */
520 if (buffer_string_is_empty(con
->server_name
)) {
521 buffer_copy_buffer(con
->server_name
, con
->uri
.authority
);
525 * create physical filename
526 * -> physical.path = docroot + rel_path
530 buffer_copy_buffer(con
->physical
.basedir
, con
->physical
.doc_root
);
531 buffer_copy_buffer(con
->physical
.path
, con
->physical
.doc_root
);
532 buffer_append_slash(con
->physical
.path
);
533 if (!buffer_string_is_empty(con
->physical
.rel_path
) &&
534 con
->physical
.rel_path
->ptr
[0] == '/') {
535 /* coverity[overflow_sink : FALSE] */
536 buffer_append_string_len(con
->physical
.path
, con
->physical
.rel_path
->ptr
+ 1, buffer_string_length(con
->physical
.rel_path
) - 1);
538 buffer_append_string_buffer(con
->physical
.path
, con
->physical
.rel_path
);
541 if (con
->conf
.log_request_handling
) {
542 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- after doc_root");
543 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Doc-Root :", con
->physical
.doc_root
);
544 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Rel-Path :", con
->physical
.rel_path
);
545 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
548 switch(r
= plugins_call_handle_physical(srv
, con
)) {
551 case HANDLER_FINISHED
:
552 case HANDLER_COMEBACK
:
553 case HANDLER_WAIT_FOR_EVENT
:
557 log_error_write(srv
, __FILE__
, __LINE__
, "");
561 if (con
->conf
.log_request_handling
) {
562 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- logical -> physical");
563 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Doc-Root :", con
->physical
.doc_root
);
564 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Basedir :", con
->physical
.basedir
);
565 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Rel-Path :", con
->physical
.rel_path
);
566 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
571 * Noone catched away the file from normal path of execution yet (like mod_access)
573 * Go on and check of the file exists at all
576 if (con
->mode
== DIRECT
) {
578 char *pathinfo
= NULL
;
580 stat_cache_entry
*sce
= NULL
;
582 if (con
->conf
.log_request_handling
) {
583 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- handling physical path");
584 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
587 if (HANDLER_ERROR
!= stat_cache_get_entry(srv
, con
, con
->physical
.path
, &sce
)) {
590 if (con
->conf
.log_request_handling
) {
591 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- file found");
592 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
595 if ((sce
->is_symlink
!= 0) && !con
->conf
.follow_symlink
) {
596 con
->http_status
= 403;
598 if (con
->conf
.log_request_handling
) {
599 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- access denied due symlink restriction");
600 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
603 buffer_reset(con
->physical
.path
);
604 return HANDLER_FINISHED
;
607 if (S_ISDIR(sce
->st
.st_mode
)) {
608 if (con
->uri
.path
->ptr
[buffer_string_length(con
->uri
.path
) - 1] != '/') {
609 /* redirect to .../ */
611 http_response_redirect_to_directory(srv
, con
);
613 return HANDLER_FINISHED
;
616 } else if (!S_ISREG(sce
->st
.st_mode
) && !sce
->is_symlink
) {
618 } else if (!S_ISREG(sce
->st
.st_mode
)) {
620 /* any special handling of non-reg files ?*/
627 con
->http_status
= 403;
629 if (con
->conf
.log_request_handling
) {
630 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- access denied");
631 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
634 buffer_reset(con
->physical
.path
);
635 return HANDLER_FINISHED
;
637 /* file name to be read was too long. return 404 */
639 con
->http_status
= 404;
641 if (con
->conf
.log_request_handling
) {
642 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- file not found");
643 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
646 buffer_reset(con
->physical
.path
);
647 return HANDLER_FINISHED
;
652 /* we have no idea what happend. let's tell the user so. */
653 con
->http_status
= 500;
654 buffer_reset(con
->physical
.path
);
656 log_error_write(srv
, __FILE__
, __LINE__
, "ssbsb",
657 "file not found ... or so: ", strerror(errno
),
659 "->", con
->physical
.path
);
661 return HANDLER_FINISHED
;
664 /* not found, perhaps PATHINFO */
666 buffer_copy_buffer(srv
->tmp_buf
, con
->physical
.path
);
670 buffer_copy_string_len(con
->physical
.path
, srv
->tmp_buf
->ptr
, slash
- srv
->tmp_buf
->ptr
);
672 buffer_copy_buffer(con
->physical
.path
, srv
->tmp_buf
);
675 if (HANDLER_ERROR
!= stat_cache_get_entry(srv
, con
, con
->physical
.path
, &sce
)) {
676 found
= S_ISREG(sce
->st
.st_mode
);
680 if (pathinfo
!= NULL
) {
683 slash
= strrchr(srv
->tmp_buf
->ptr
, '/');
685 if (pathinfo
!= NULL
) {
690 if (slash
) pathinfo
= slash
;
691 } while ((found
== 0) && (slash
!= NULL
) && ((size_t)(slash
- srv
->tmp_buf
->ptr
) > (buffer_string_length(con
->physical
.basedir
) - 1)));
694 /* no it really doesn't exists */
695 con
->http_status
= 404;
697 if (con
->conf
.log_file_not_found
) {
698 log_error_write(srv
, __FILE__
, __LINE__
, "sbsb",
699 "file not found:", con
->uri
.path
,
700 "->", con
->physical
.path
);
703 buffer_reset(con
->physical
.path
);
705 return HANDLER_FINISHED
;
709 if ((sce
->is_symlink
!= 0) && !con
->conf
.follow_symlink
) {
710 con
->http_status
= 403;
712 if (con
->conf
.log_request_handling
) {
713 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- access denied due symlink restriction");
714 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
717 buffer_reset(con
->physical
.path
);
718 return HANDLER_FINISHED
;
722 /* we have a PATHINFO */
724 size_t len
= strlen(pathinfo
), reqlen
;
725 if (con
->conf
.force_lowercase_filenames
726 && len
<= (reqlen
= buffer_string_length(con
->request
.uri
))
727 && 0 == strncasecmp(con
->request
.uri
->ptr
+ reqlen
- len
, pathinfo
, len
)) {
728 /* attempt to preserve case-insensitive PATH_INFO
729 * (works in common case where mod_alias, mod_magnet, and other modules
730 * have not modified the PATH_INFO portion of request URI, or did so
731 * with exactly the PATH_INFO desired) */
732 buffer_copy_string_len(con
->request
.pathinfo
, con
->request
.uri
->ptr
+ reqlen
- len
, len
);
734 buffer_copy_string_len(con
->request
.pathinfo
, pathinfo
, len
);
741 buffer_string_set_length(con
->uri
.path
, buffer_string_length(con
->uri
.path
) - len
);
744 if (con
->conf
.log_request_handling
) {
745 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- after pathinfo check");
746 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
747 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "URI :", con
->uri
.path
);
748 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Pathinfo :", con
->request
.pathinfo
);
752 if (con
->conf
.log_request_handling
) {
753 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- handling subrequest");
754 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "Path :", con
->physical
.path
);
757 /* call the handlers */
758 switch(r
= plugins_call_handle_subrequest_start(srv
, con
)) {
760 /* request was not handled */
762 case HANDLER_FINISHED
:
764 if (con
->conf
.log_request_handling
) {
765 log_error_write(srv
, __FILE__
, __LINE__
, "s", "-- subrequest finished");
768 /* something strange happend */
772 /* if we are still here, no one wanted the file, status 403 is ok I think */
774 if (con
->mode
== DIRECT
&& con
->http_status
== 0) {
775 switch (con
->request
.http_method
) {
776 case HTTP_METHOD_OPTIONS
:
777 con
->http_status
= 200;
780 con
->http_status
= 403;
783 return HANDLER_FINISHED
;
788 switch(r
= plugins_call_handle_subrequest(srv
, con
)) {
790 /* request was not handled, looks like we are done */
791 return HANDLER_FINISHED
;
792 case HANDLER_FINISHED
:
793 /* request is finished */
795 /* something strange happend */
800 return HANDLER_COMEBACK
;