📄 mod_proxy_ftp.c
字号:
while (path[1] == '/') /* collapse multiple leading slashes to one */ ++path; reldir = strrchr(path, '/'); if (reldir != NULL && ftp_check_globbingchars(reldir)) { wildcard = &reldir[1]; reldir[0] = '\0'; /* strip off the wildcard suffix */ } /* Copy path, strip (all except the last) trailing slashes */ /* (the trailing slash is needed for the dir component loop below) */ path = dir = apr_pstrcat(p, path, "/", NULL); for (n = strlen(path); n > 1 && path[n - 1] == '/' && path[n - 2] == '/'; --n) path[n - 1] = '\0'; /* Add a link to the root directory (if %2f hack was used) */ str = (basedir[0] != '\0') ? "<a href=\"/%2f/\">%2f</a>/" : ""; /* print "ftp://host/" */ escpath = ap_escape_html(p, path); str = apr_psprintf(p, DOCTYPE_HTML_3_2 "<html>\n <head>\n <title>%s%s%s</title>\n" "<base href=\"%s%s%s\">\n" " </head>\n" " <body>\n <h2>Directory of " "<a href=\"/\">%s</a>/%s", site, basedir, escpath, site, basedir, escpath, site, str); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); for (dir = path+1; (dir = strchr(dir, '/')) != NULL; ) { *dir = '\0'; if ((reldir = strrchr(path+1, '/'))==NULL) { reldir = path+1; } else ++reldir; /* print "path/" component */ str = apr_psprintf(p, "<a href=\"%s%s/\">%s</a>/", basedir, ap_escape_uri(p, path), ap_escape_html(p, reldir)); *dir = '/'; while (*dir == '/') ++dir; APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); } if (wildcard != NULL) { wildcard = ap_escape_html(p, wildcard); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(wildcard, strlen(wildcard), p, c->bucket_alloc)); } /* If the caller has determined the current directory, and it differs */ /* from what the client requested, then show the real name */ if (pwd == NULL || strncmp(pwd, path, strlen(pwd)) == 0) { str = apr_psprintf(p, "</h2>\n\n <hr />\n\n<pre>"); } else { str = apr_psprintf(p, "</h2>\n\n(%s)\n\n <hr />\n\n<pre>", ap_escape_html(p, pwd)); } APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); /* print README */ if (readme) { str = apr_psprintf(p, "%s\n</pre>\n\n<hr />\n\n<pre>\n", ap_escape_html(p, readme)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); } /* make sure page intro gets sent out */ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc)); if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { return rv; } apr_brigade_cleanup(out); ctx->state = BODY; } /* loop through each line of directory */ while (BODY == ctx->state) { char *filename; int found = 0; int eos = 0; ap_regex_t *re = NULL; ap_regmatch_t re_result[LS_REG_MATCH]; /* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */ re = ap_pregcomp(p, LS_REG_PATTERN, AP_REG_EXTENDED); ap_assert(re != NULL); /* get a complete line */ /* if the buffer overruns - throw data away */ while (!found && !APR_BRIGADE_EMPTY(ctx->in)) { char *pos, *response; apr_size_t len, max; apr_bucket *e; e = APR_BRIGADE_FIRST(ctx->in); if (APR_BUCKET_IS_EOS(e)) { eos = 1; break; } if (APR_SUCCESS != (rv = apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ))) { return rv; } pos = memchr(response, APR_ASCII_LF, len); if (pos != NULL) { if ((response + len) != (pos + 1)) { len = pos - response + 1; apr_bucket_split(e, pos - response + 1); } found = 1; } max = sizeof(ctx->buffer) - strlen(ctx->buffer) - 1; if (len > max) { len = max; } /* len+1 to leave space for the trailing nil char */ apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len+1); APR_BUCKET_REMOVE(e); apr_bucket_destroy(e); } /* EOS? jump to footer */ if (eos) { ctx->state = FOOTER; break; } /* not complete? leave and try get some more */ if (!found) { return APR_SUCCESS; } { apr_size_t n = strlen(ctx->buffer); if (ctx->buffer[n-1] == CRLF[1]) /* strip trailing '\n' */ ctx->buffer[--n] = '\0'; if (ctx->buffer[n-1] == CRLF[0]) /* strip trailing '\r' if present */ ctx->buffer[--n] = '\0'; } /* a symlink? */ if (ctx->buffer[0] == 'l' && (filename = strstr(ctx->buffer, " -> ")) != NULL) { char *link_ptr = filename; do { filename--; } while (filename[0] != ' ' && filename > ctx->buffer); if (filename > ctx->buffer) *(filename++) = '\0'; *(link_ptr++) = '\0'; str = apr_psprintf(p, "%s <a href=\"%s\">%s %s</a>\n", ap_escape_html(p, ctx->buffer), ap_escape_uri(p, filename), ap_escape_html(p, filename), ap_escape_html(p, link_ptr)); } /* a directory/file? */ else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) { int searchidx = 0; char *searchptr = NULL; int firstfile = 1; if (apr_isdigit(ctx->buffer[0])) { /* handle DOS dir */ searchptr = strchr(ctx->buffer, '<'); if (searchptr != NULL) *searchptr = '['; searchptr = strchr(ctx->buffer, '>'); if (searchptr != NULL) *searchptr = ']'; } filename = strrchr(ctx->buffer, ' '); if (filename == NULL) { /* Line is broken. Ignore it. */ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy_ftp: could not parse line %s", ctx->buffer); /* erase buffer for next time around */ ctx->buffer[0] = 0; continue; /* while state is BODY */ } *(filename++) = '\0'; /* handle filenames with spaces in 'em */ if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) { firstfile = 0; searchidx = filename - ctx->buffer; } else if (searchidx != 0 && ctx->buffer[searchidx] != 0) { *(--filename) = ' '; ctx->buffer[searchidx - 1] = '\0'; filename = &ctx->buffer[searchidx]; } /* Append a slash to the HREF link for directories */ if (!strcmp(filename, ".") || !strcmp(filename, "..") || ctx->buffer[0] == 'd') { str = apr_psprintf(p, "%s <a href=\"%s/\">%s</a>\n", ap_escape_html(p, ctx->buffer), ap_escape_uri(p, filename), ap_escape_html(p, filename)); } else { str = apr_psprintf(p, "%s <a href=\"%s\">%s</a>\n", ap_escape_html(p, ctx->buffer), ap_escape_uri(p, filename), ap_escape_html(p, filename)); } } /* Try a fallback for listings in the format of "ls -s1" */ else if (0 == ap_regexec(re, ctx->buffer, LS_REG_MATCH, re_result, 0)) { filename = apr_pstrndup(p, &ctx->buffer[re_result[2].rm_so], re_result[2].rm_eo - re_result[2].rm_so); str = apr_pstrcat(p, ap_escape_html(p, apr_pstrndup(p, ctx->buffer, re_result[2].rm_so)), "<a href=\"", ap_escape_uri(p, filename), "\">", ap_escape_html(p, filename), "</a>\n", NULL); } else { strcat(ctx->buffer, "\n"); /* re-append the newline */ str = ap_escape_html(p, ctx->buffer); } /* erase buffer for next time around */ ctx->buffer[0] = 0; APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc)); if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { return rv; } apr_brigade_cleanup(out); } if (FOOTER == ctx->state) { str = apr_psprintf(p, "</pre>\n\n <hr />\n\n %s\n\n </body>\n</html>\n", ap_psignature("", r)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p, c->bucket_alloc)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc)); APR_BRIGADE_INSERT_TAIL(out, apr_bucket_eos_create(c->bucket_alloc)); if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) { return rv; } apr_brigade_destroy(out); } return APR_SUCCESS;}/* * Generic "send FTP command to server" routine, using the control socket. * Returns the FTP returncode (3 digit code) * Allows for tracing the FTP protocol (in LogLevel debug) */static intproxy_ftp_command(const char *cmd, request_rec *r, conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char **pmessage){ char *crlf; int rc; char message[HUGE_STRING_LEN]; /* If cmd == NULL, we retrieve the next ftp response line */ if (cmd != NULL) { conn_rec *c = r->connection; APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(cmd, strlen(cmd), r->pool, c->bucket_alloc)); APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(c->bucket_alloc)); ap_pass_brigade(ftp_ctrl->output_filters, bb); /* strip off the CRLF for logging */ apr_cpystrn(message, cmd, sizeof(message)); if ((crlf = strchr(message, '\r')) != NULL || (crlf = strchr(message, '\n')) != NULL) *crlf = '\0'; if (strncmp(message,"PASS ", 5) == 0) strcpy(&message[5], "****"); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy:>FTP: %s", message); } rc = ftp_getrc_msg(ftp_ctrl, bb, message, sizeof message); if (rc == -1 || rc == 421) strcpy(message,"<unable to read result>"); if ((crlf = strchr(message, '\r')) != NULL || (crlf = strchr(message, '\n')) != NULL) *crlf = '\0'; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy:<FTP: %3.3u %s", rc, message); if (pmessage != NULL) *pmessage = apr_pstrdup(r->pool, message); return rc;}/* Set ftp server to TYPE {A,I,E} before transfer of a directory or file */static int ftp_set_TYPE(char xfer_type, request_rec *r, conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char **pmessage){ char old_type[2] = { 'A', '\0' }; /* After logon, mode is ASCII */ int ret = HTTP_OK; int rc; /* set desired type */ old_type[0] = xfer_type; rc = proxy_ftp_command(apr_pstrcat(r->pool, "TYPE ", old_type, CRLF, NULL), r, ftp_ctrl, bb, pmessage);/* responses: 200, 421, 500, 501, 504, 530 */ /* 200 Command okay. */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 504 Command not implemented for that parameter. */ /* 530 Not logged in. */ if (rc == -1 || rc == 421) { ret = ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } else if (rc != 200 && rc != 504) { ret = ap_proxyerror(r, HTTP_BAD_GATEWAY, "Unable to set transfer type"); }/* Allow not implemented */ else if (rc == 504)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -