version 1.155, 2017/06/20 17:24:35 |
version 1.161, 2018/10/19 21:10:56 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@usta.de> |
* Copyright (c) 2014, 2015, 2016, 2017, 2018 Ingo Schwarze <schwarze@usta.de> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
static void html_print(const char *); |
static void html_print(const char *); |
static void html_putchar(char); |
static void html_putchar(char); |
static int http_decode(char *); |
static int http_decode(char *); |
|
static void http_encode(const char *p); |
static void parse_manpath_conf(struct req *); |
static void parse_manpath_conf(struct req *); |
static void parse_path_info(struct req *req, const char *path); |
static void parse_path_info(struct req *req, const char *path); |
static void parse_query_string(struct req *, const char *); |
static void parse_query_string(struct req *, const char *); |
Line 90 static void resp_format(const struct req *, const ch |
|
Line 91 static void resp_format(const struct req *, const ch |
|
static void resp_searchform(const struct req *, enum focus); |
static void resp_searchform(const struct req *, enum focus); |
static void resp_show(const struct req *, const char *); |
static void resp_show(const struct req *, const char *); |
static void set_query_attr(char **, char **); |
static void set_query_attr(char **, char **); |
|
static int validate_arch(const char *); |
static int validate_filename(const char *); |
static int validate_filename(const char *); |
static int validate_manpath(const struct req *, const char *); |
static int validate_manpath(const struct req *, const char *); |
static int validate_urifrag(const char *); |
static int validate_urifrag(const char *); |
Line 316 http_decode(char *p) |
|
Line 318 http_decode(char *p) |
|
} |
} |
|
|
static void |
static void |
|
http_encode(const char *p) |
|
{ |
|
for (; *p != '\0'; p++) { |
|
if (isalnum((unsigned char)*p) == 0 && |
|
strchr("-._~", *p) == NULL) |
|
printf("%%%02.2X", (unsigned char)*p); |
|
else |
|
putchar(*p); |
|
} |
|
} |
|
|
|
static void |
resp_begin_http(int code, const char *msg) |
resp_begin_http(int code, const char *msg) |
{ |
{ |
|
|
Line 356 resp_begin_html(int code, const char *msg, const char |
|
Line 370 resp_begin_html(int code, const char *msg, const char |
|
"<html>\n" |
"<html>\n" |
"<head>\n" |
"<head>\n" |
" <meta charset=\"UTF-8\"/>\n" |
" <meta charset=\"UTF-8\"/>\n" |
|
" <meta name=\"viewport\"" |
|
" content=\"width=device-width, initial-scale=1.0\">\n" |
" <link rel=\"stylesheet\" href=\"%s/mandoc.css\"" |
" <link rel=\"stylesheet\" href=\"%s/mandoc.css\"" |
" type=\"text/css\" media=\"all\">\n" |
" type=\"text/css\" media=\"all\">\n" |
" <title>", |
" <title>", |
Line 398 resp_searchform(const struct req *req, enum focus focu |
|
Line 414 resp_searchform(const struct req *req, enum focus focu |
|
|
|
/* Write query input box. */ |
/* Write query input box. */ |
|
|
printf(" <input type=\"text\" name=\"query\" value=\""); |
printf(" <input type=\"search\" name=\"query\" value=\""); |
if (req->q.query != NULL) |
if (req->q.query != NULL) |
html_print(req->q.query); |
html_print(req->q.query); |
printf( "\" size=\"40\""); |
printf( "\" size=\"40\""); |
Line 434 resp_searchform(const struct req *req, enum focus focu |
|
Line 450 resp_searchform(const struct req *req, enum focus focu |
|
printf(" selected=\"selected\""); |
printf(" selected=\"selected\""); |
puts(">All Architectures</option>"); |
puts(">All Architectures</option>"); |
for (i = 0; i < arch_MAX; i++) { |
for (i = 0; i < arch_MAX; i++) { |
printf(" <option value=\"%s\"", arch_names[i]); |
printf(" <option"); |
if (NULL != req->q.arch && |
if (NULL != req->q.arch && |
0 == strcmp(arch_names[i], req->q.arch)) |
0 == strcmp(arch_names[i], req->q.arch)) |
printf(" selected=\"selected\""); |
printf(" selected=\"selected\""); |
Line 447 resp_searchform(const struct req *req, enum focus focu |
|
Line 463 resp_searchform(const struct req *req, enum focus focu |
|
if (req->psz > 1) { |
if (req->psz > 1) { |
puts(" <select name=\"manpath\">"); |
puts(" <select name=\"manpath\">"); |
for (i = 0; i < (int)req->psz; i++) { |
for (i = 0; i < (int)req->psz; i++) { |
printf(" <option "); |
printf(" <option"); |
if (strcmp(req->q.manpath, req->p[i]) == 0) |
if (strcmp(req->q.manpath, req->p[i]) == 0) |
printf("selected=\"selected\" "); |
printf(" selected=\"selected\""); |
printf("value=\""); |
printf(">"); |
html_print(req->p[i]); |
html_print(req->p[i]); |
printf("\">"); |
|
html_print(req->p[i]); |
|
puts("</option>"); |
puts("</option>"); |
} |
} |
puts(" </select>"); |
puts(" </select>"); |
Line 490 validate_manpath(const struct req *req, const char* ma |
|
Line 504 validate_manpath(const struct req *req, const char* ma |
|
} |
} |
|
|
static int |
static int |
|
validate_arch(const char *arch) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < arch_MAX; i++) |
|
if (strcmp(arch, arch_names[i]) == 0) |
|
return 1; |
|
|
|
return 0; |
|
} |
|
|
|
static int |
validate_filename(const char *file) |
validate_filename(const char *file) |
{ |
{ |
|
|
Line 562 pg_redirect(const struct req *req, const char *name) |
|
Line 588 pg_redirect(const struct req *req, const char *name) |
|
printf("%s/", req->q.manpath); |
printf("%s/", req->q.manpath); |
if (req->q.arch != NULL) |
if (req->q.arch != NULL) |
printf("%s/", req->q.arch); |
printf("%s/", req->q.arch); |
printf("%s", name); |
http_encode(name); |
if (req->q.sec != NULL) |
if (req->q.sec != NULL) { |
printf(".%s", req->q.sec); |
putchar('.'); |
|
http_encode(req->q.sec); |
|
} |
printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"); |
printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"); |
} |
} |
|
|
Line 832 resp_format(const struct req *req, const char *file) |
|
Line 860 resp_format(const struct req *req, const char *file) |
|
|
|
mchars_alloc(); |
mchars_alloc(); |
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, |
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, |
MANDOCLEVEL_BADARG, NULL, req->q.manpath); |
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath); |
mparse_readfd(mp, fd, file); |
mparse_readfd(mp, fd, file); |
close(fd); |
close(fd); |
|
|
memset(&conf, 0, sizeof(conf)); |
memset(&conf, 0, sizeof(conf)); |
conf.fragment = 1; |
conf.fragment = 1; |
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); |
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); |
|
conf.toc = 1; |
usepath = strcmp(req->q.manpath, req->p[0]); |
usepath = strcmp(req->q.manpath, req->p[0]); |
mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", |
mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", |
scriptname, *scriptname == '\0' ? "" : "/", |
scriptname, *scriptname == '\0' ? "" : "/", |
|
|
return EXIT_FAILURE; |
return EXIT_FAILURE; |
} |
} |
|
|
if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) { |
if (req.q.arch != NULL && validate_arch(req.q.arch) == 0) { |
pg_error_badrequest( |
pg_error_badrequest( |
"You specified an invalid architecture."); |
"You specified an invalid architecture."); |
return EXIT_FAILURE; |
return EXIT_FAILURE; |
|
|
} |
} |
|
|
/* |
/* |
* If PATH_INFO is not a file name, translate it to a query. |
* Translate PATH_INFO to a query. |
*/ |
*/ |
static void |
static void |
parse_path_info(struct req *req, const char *path) |
parse_path_info(struct req *req, const char *path) |
{ |
{ |
char *dir[4]; |
const char *name, *sec, *end; |
int i; |
|
|
|
req->isquery = 0; |
req->isquery = 0; |
req->q.equal = 1; |
req->q.equal = 1; |
req->q.manpath = mandoc_strdup(path); |
req->q.manpath = NULL; |
req->q.arch = NULL; |
req->q.arch = NULL; |
|
|
/* Mandatory manual page name. */ |
/* Mandatory manual page name. */ |
if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) { |
if ((name = strrchr(path, '/')) == NULL) |
req->q.query = req->q.manpath; |
name = path; |
req->q.manpath = NULL; |
else |
} else |
name++; |
*req->q.query++ = '\0'; |
|
|
|
/* Optional trailing section. */ |
/* Optional trailing section. */ |
if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) { |
sec = strrchr(name, '.'); |
if(isdigit((unsigned char)req->q.sec[1])) { |
if (sec != NULL && isdigit((unsigned char)*++sec)) { |
*req->q.sec++ = '\0'; |
req->q.query = mandoc_strndup(name, sec - name - 1); |
req->q.sec = mandoc_strdup(req->q.sec); |
req->q.sec = mandoc_strdup(sec); |
} else |
} else { |
req->q.sec = NULL; |
req->q.query = mandoc_strdup(name); |
|
req->q.sec = NULL; |
} |
} |
|
|
/* Handle the case of name[.section] only. */ |
/* Handle the case of name[.section] only. */ |
if (req->q.manpath == NULL) |
if (name == path) |
return; |
return; |
req->q.query = mandoc_strdup(req->q.query); |
|
|
|
/* Split directory components. */ |
|
dir[i = 0] = req->q.manpath; |
|
while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) { |
|
if (++i == 3) { |
|
pg_error_badrequest( |
|
"You specified too many directory components."); |
|
exit(EXIT_FAILURE); |
|
} |
|
*dir[i]++ = '\0'; |
|
} |
|
|
|
/* Optional manpath. */ |
/* Optional manpath. */ |
if ((i = validate_manpath(req, req->q.manpath)) == 0) |
end = strchr(path, '/'); |
|
req->q.manpath = mandoc_strndup(path, end - path); |
|
if (validate_manpath(req, req->q.manpath)) { |
|
path = end + 1; |
|
if (name == path) |
|
return; |
|
} else { |
|
free(req->q.manpath); |
req->q.manpath = NULL; |
req->q.manpath = NULL; |
else if (dir[1] == NULL) |
} |
return; |
|
|
|
/* Optional section. */ |
/* Optional section. */ |
if (strncmp(dir[i], "man", 3) == 0) { |
if (strncmp(path, "man", 3) == 0) { |
|
path += 3; |
|
end = strchr(path, '/'); |
free(req->q.sec); |
free(req->q.sec); |
req->q.sec = mandoc_strdup(dir[i++] + 3); |
req->q.sec = mandoc_strndup(path, end - path); |
|
path = end + 1; |
|
if (name == path) |
|
return; |
} |
} |
if (dir[i] == NULL) { |
|
if (req->q.manpath == NULL) |
/* Optional architecture. */ |
free(dir[0]); |
end = strchr(path, '/'); |
return; |
if (end + 1 != name) { |
|
pg_error_badrequest( |
|
"You specified too many directory components."); |
|
exit(EXIT_FAILURE); |
} |
} |
if (dir[i + 1] != NULL) { |
req->q.arch = mandoc_strndup(path, end - path); |
|
if (validate_arch(req->q.arch) == 0) { |
pg_error_badrequest( |
pg_error_badrequest( |
"You specified an invalid directory component."); |
"You specified an invalid directory component."); |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
} |
} |
|
|
/* Optional architecture. */ |
|
if (i) { |
|
req->q.arch = mandoc_strdup(dir[i]); |
|
if (req->q.manpath == NULL) |
|
free(dir[0]); |
|
} else |
|
req->q.arch = dir[0]; |
|
} |
} |
|
|
/* |
/* |