You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apache-bugdb@apache.org by Patrick ASTY <pa...@micronet.fr> on 2000/05/11 10:41:26 UTC
mod_proxy/6069: PATCH to enable PUT for mod_proxy
>Number: 6069
>Category: mod_proxy
>Synopsis: PATCH to enable PUT for mod_proxy
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: apache
>State: open
>Class: change-request
>Submitter-Id: apache
>Arrival-Date: Thu May 11 01:50:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: pasty@micronet.fr
>Release: 1.3.12
>Organization:
apache
>Environment:
All (but only really tested on Linux)
>Description:
PUT method is not supported by mod_proxy.
Following a patch to enable it.
>How-To-Repeat:
% telnet apache_proxy port
PUT ftp://user:pass@host/uri
Content-Length: nnn
data...
%
>Fix:
*** src/modules/proxy/mod_proxy.h.orig Wed May 10 06:35:01 2000
--- src/modules/proxy/mod_proxy.h Thu May 11 09:55:57 2000
***************
*** 300,305 ****
--- 300,306 ----
const char *ap_proxy_date_canon(pool *p, const char *x);
table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c);
+ long int ap_proxy_receive_fb(BUFF *f, request_rec *r, cache_req *c);
void ap_proxy_send_headers(request_rec *r, const char *respline, table *hdrs);
int ap_proxy_liststr(const char *list, const char *val);
void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
*** src/modules/proxy/proxy_ftp.c.orig Wed May 10 06:06:04 2000
--- src/modules/proxy/proxy_ftp.c Thu May 11 09:55:12 2000
***************
*** 408,413 ****
--- 408,471 ----
return total_bytes_sent;
}
+ static long int send_put(BUFF *f, request_rec *r, cache_req *c, char *cwd, char *msg)
+ {
+ char buf[IOBUFSIZE];
+ unsigned long total_bytes_sent = 0;
+ register int n;
+ conn_rec *con = r->connection;
+ char *dir, *path, *reldir, *site;
+
+ /* Save "scheme://site" prefix without password */
+ site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
+ /* ... and path without query args */
+ path = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITSITEPART|UNP_OMITQUERY);
+ (void)decodeenc(path);
+
+ /* Copy path, strip (all except the last) trailing slashes */
+ path = dir = ap_pstrcat(r->pool, path, "/", NULL);
+ while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
+ path[n-1] = '\0';
+
+ /* print "ftp://host/" */
+ n = ap_snprintf(buf, sizeof(buf), DOCTYPE_HTML_3_2
+ "<HTML><HEAD><TITLE>%s%s</TITLE>\n"
+ "<BASE HREF=\"%s%s\"></HEAD>\n"
+ "<BODY><H2>Put for "
+ "<A HREF=\"/\">%s</A>/",
+ site, path, site, path, site);
+ total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
+
+ while ((dir = strchr(dir+1, '/')) != NULL)
+ {
+ *dir = '\0';
+ if ((reldir = strrchr(path+1, '/'))==NULL)
+ reldir = path+1;
+ else
+ ++reldir;
+ /* print "path/" component */
+ ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
+ total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
+ *dir = '/';
+ }
+ /* If the caller has determined the current directory, and it differs */
+ /* from what the client requested, then show the real name */
+ if (cwd == NULL || strncmp (cwd, path, strlen(cwd)) == 0) {
+ ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
+ } else {
+ ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR>", cwd);
+ }
+ total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
+ total_bytes_sent += ap_proxy_bputs2(msg, con->client, c);
+ total_bytes_sent += ap_proxy_bputs2("<HR>\n", con->client, c);
+ total_bytes_sent += ap_proxy_bputs2(ap_psignature("", r), con->client, c);
+ total_bytes_sent += ap_proxy_bputs2("</BODY></HTML>\n", con->client, c);
+
+ ap_bflush(con->client);
+
+ return total_bytes_sent;
+ }
+
/* Common routine for failed authorization (i.e., missing or wrong password)
* to an ftp service. This causes most browsers to retry the request
* with username and password (which was presumably queried from the user)
***************
*** 485,491 ****
/* we only support GET and HEAD */
! if (r->method_number != M_GET)
return HTTP_NOT_IMPLEMENTED;
/* We break the URL into host, port, path-search */
--- 543,549 ----
/* we only support GET, HEAD and PUT */
! if (r->method_number != M_GET && r->method_number != M_PUT)
return HTTP_NOT_IMPLEMENTED;
/* We break the URL into host, port, path-search */
***************
*** 943,949 ****
if (len == 0) {
parms = "d";
}
! else {
ap_bvputs(f, "SIZE ", path, CRLF, NULL);
ap_bflush(f);
Explain1("FTP: SIZE %s", path);
--- 1001,1007 ----
if (len == 0) {
parms = "d";
}
! else if (r->method_number != M_PUT) {
ap_bvputs(f, "SIZE ", path, CRLF, NULL);
ap_bflush(f);
Explain1("FTP: SIZE %s", path);
***************
*** 1028,1035 ****
Explain1("FTP: LIST %s", (len == 0 ? "" : path));
}
else {
! ap_bvputs(f, "RETR ", path, CRLF, NULL);
! Explain1("FTP: RETR %s", path);
}
ap_bflush(f);
/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
--- 1086,1099 ----
Explain1("FTP: LIST %s", (len == 0 ? "" : path));
}
else {
! if (r->method_number == M_GET) {
! ap_bvputs(f, "RETR ", path, CRLF, NULL);
! Explain1("FTP: RETR %s", path);
! }
! else {
! ap_bvputs(f, "STOR ", path, CRLF, NULL);
! Explain1("FTP: STOR %s", path);
! }
}
ap_bflush(f);
/* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
***************
*** 1055,1061 ****
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
! if (rc == 550) {
Explain0("FTP: RETR failed, trying LIST instead");
parms = "d";
ap_bvputs(f, "CWD ", path, CRLF, NULL);
--- 1119,1125 ----
return ap_proxyerror(r, HTTP_BAD_GATEWAY,
"Error reading from remote server");
}
! if (rc == 550 && r->method_number != M_PUT) {
Explain0("FTP: RETR failed, trying LIST instead");
parms = "d";
ap_bvputs(f, "CWD ", path, CRLF, NULL);
***************
*** 1137,1142 ****
--- 1201,1208 ----
if (parms[0] == 'd')
ap_table_setn(resp_hdrs, "Content-Type", "text/html");
+ else if (r->method_number == M_PUT)
+ ap_table_setn(resp_hdrs, "Content-Type", "text/html");
else {
if (r->content_type != NULL) {
ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
***************
*** 1157,1162 ****
--- 1223,1231 ----
}
/* check if NoCache directive on this host */
+ if (r->method_number == M_PUT)
+ nocache = 1;
+ else
for (i = 0; i < conf->nocaches->nelts; i++) {
if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
|| destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
***************
*** 1226,1231 ****
--- 1295,1308 ----
r->sent_bodyct = 1;
/* send body */
if (!r->header_only) {
+ if (r->method_number == M_PUT) {
+ /* we need ap_*_client_block() for ap_proxy_receive_fb()... */
+ if (ap_setup_client_block(r, REQUEST_CHUNKED_ERROR) == OK &&
+ ap_should_client_block(r))
+ ap_proxy_receive_fb(data, r, c);
+ ap_bclose(data); /* DATA must be closed to get rc */
+ }
+ else {
if (parms[0] != 'd') {
/* we need to set this for ap_proxy_send_fb()... */
if (c != NULL)
***************
*** 1233,1248 ****
ap_proxy_send_fb(data, r, c);
} else
send_dir(data, r, c, cwd);
if (rc == 125 || rc == 150)
rc = ftp_getrc(f);
/* XXX: we checked for 125||150||226||250 above. This is redundant. */
if (rc != 226 && rc != 250)
/* XXX: we no longer log an "error writing to c->tempfile" - should we? */
c = ap_proxy_cache_error(c);
}
! else {
/* abort the transfer */
ap_bputs("ABOR" CRLF, f);
ap_bflush(f);
--- 1310,1330 ----
ap_proxy_send_fb(data, r, c);
} else
send_dir(data, r, c, cwd);
+ }
if (rc == 125 || rc == 150)
rc = ftp_getrc(f);
/* XXX: we checked for 125||150||226||250 above. This is redundant. */
+ if (r->method_number == M_PUT)
+ send_put(data, r, c, cwd, ap_psprintf(p, "Done with status %d", rc));
+ else
if (rc != 226 && rc != 250)
/* XXX: we no longer log an "error writing to c->tempfile" - should we? */
c = ap_proxy_cache_error(c);
}
! if (r->header_only || (r->method_number == M_PUT &&
! r->connection->aborted)) {
/* abort the transfer */
ap_bputs("ABOR" CRLF, f);
ap_bflush(f);
*** src/modules/proxy/proxy_util.c.orig Wed May 10 11:28:53 2000
--- src/modules/proxy/proxy_util.c Thu May 11 09:52:37 2000
***************
*** 621,626 ****
--- 621,669 ----
return total_bytes_rcvd;
}
+ long int ap_proxy_receive_fb(BUFF *f, request_rec *r, cache_req *c)
+ {
+ int ok;
+ char buf[IOBUFSIZE];
+ long total_bytes_sent;
+ register int n, o, w;
+ conn_rec *con = r->connection;
+
+ /* Loop and ap_get_client_block() while we can successfully read & write. */
+ total_bytes_sent = 0;
+ for (ok = 1; ok; ) {
+
+ /* Read block from client */
+ n = ap_get_client_block(r, buf, IOBUFSIZE);
+
+ if (n == -1) { /* input error */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
+ "proxy: error reading from %s", c->url);
+ break;
+ }
+ if (n == 0)
+ break; /* EOF */
+ o = 0;
+ total_bytes_sent += n;
+
+ /* Write the block to the server, detect aborted transfers */
+ while (!con->aborted && n > 0) {
+ w = ap_bwrite(f, &buf[o], n);
+ if (w <= 0) {
+ con->aborted = 1;
+ break;
+ }
+ n -= w;
+ o += w;
+ } /* while client alive and more data to send */
+ } /* loop and ap_bread while "ok" */
+
+ if (!con->aborted)
+ ap_bflush(f);
+
+ return total_bytes_sent;
+ }
+
/*
* Sends response line and headers. Uses the client fd and the
* headers_out array from the passed request_rec to talk to the client
>Release-Note:
>Audit-Trail:
>Unformatted:
[In order for any reply to be added to the PR database, you need]
[to include <ap...@Apache.Org> in the Cc line and make sure the]
[subject line starts with the report component and number, with ]
[or without any 'Re:' prefixes (such as "general/1098:" or ]
["Re: general/1098:"). If the subject doesn't match this ]
[pattern, your message will be misfiled and ignored. The ]
["apbugs" address is not added to the Cc line of messages from ]
[the database automatically because of the potential for mail ]
[loops. If you do not include this Cc, your reply may be ig- ]
[nored unless you are responding to an explicit request from a ]
[developer. Reply only with text; DO NOT SEND ATTACHMENTS! ]