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!     ]