Forcing additional headers with Location: redirect

2009-01-06 Thread Juhani Connolly
I'm currently working on modifying a php based application into an apache 
module.


The short of it is that I want to send a Location header with a 0 content 
length message and headers for cache-control and pragma.
Setting the headers, and returning HTTP_MOVED_TEMPORARILY the additional 
headers are stripped and the default message is sent.
Using ErrorDocument in my httpd.conf to use a 0 length file, the content 
length is correctly set to 0, but even the Location header gets stripped.
I am pretty sure the cause of my issue is unrelated to the additional 
headers, just needing me to send no content which is confusing the problem 
handsets. How can I cause this behaviour?


For anyone interested, the background of the situation, some source after 
the background:


In addition to logging an access to an image, this module will redirect the 
request based on some parameters to a different server. The php version 
would send Location, pragma: no-cache, cache-control: no-cache, 
must-revalidate and 0 content length, which worked perfectly for all 
clients.
Within the module I have set the location header as well as the pragma and 
cache-control, however only the location will go through, and the default 
302 message is sent. This is not generally a problem, except for with one of 
the local mobile phone handset manufacturers which fails to redirect the 
image correctly claiming a bad image.
Thus I am attempting to emulate the behaviour of the php, being unsure of 
which part is causing the problem. Most likely it would be the content being 
sent confusing the handset. Honestly I'd like to just ignore the particular 
manufacturer, but this is not an option.


Some source(stripped down to the essentials... In the actual version there's 
error handling and whatnot):


curl_easy_setopt(hCurl, CURLOPT_URL, adUrl);  // url to get the redirect 
location from

curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, outUrl);
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, outUrlWrite);

if(curl_easy_perform(hCurl) == 0)
{
 apr_table_setn(r-headers_out, Location, outUrl);
}

r-content_type = CONTENT_TYPE_MOBILE;

apr_table_setn(r-headers_out, Cache-Control, no-cache, 
must-revalidate);

apr_table_setn(r-headers_out, Pragma, no-cache);

curl_easy_cleanup(hCurl);

return HTTP_MOVED_TEMPORARILY; 



Re: Forcing additional headers with Location: redirect

2009-01-06 Thread Sorin Manolache
On Wed, Jan 7, 2009 at 07:14, Juhani Connolly juh...@ninja.co.jp wrote:
 I'm currently working on modifying a php based application into an apache
 module.

 The short of it is that I want to send a Location header with a 0 content
 length message and headers for cache-control and pragma.
 Setting the headers, and returning HTTP_MOVED_TEMPORARILY the additional
 headers are stripped and the default message is sent.
 Using ErrorDocument in my httpd.conf to use a 0 length file, the content
 length is correctly set to 0, but even the Location header gets stripped.
 I am pretty sure the cause of my issue is unrelated to the additional
 headers, just needing me to send no content which is confusing the problem
 handsets. How can I cause this behaviour?

 For anyone interested, the background of the situation, some source after
 the background:

 In addition to logging an access to an image, this module will redirect the
 request based on some parameters to a different server. The php version
 would send Location, pragma: no-cache, cache-control: no-cache,
 must-revalidate and 0 content length, which worked perfectly for all
 clients.
 Within the module I have set the location header as well as the pragma and
 cache-control, however only the location will go through, and the default
 302 message is sent. This is not generally a problem, except for with one of
 the local mobile phone handset manufacturers which fails to redirect the
 image correctly claiming a bad image.
 Thus I am attempting to emulate the behaviour of the php, being unsure of
 which part is causing the problem. Most likely it would be the content being
 sent confusing the handset. Honestly I'd like to just ignore the particular
 manufacturer, but this is not an option.

 Some source(stripped down to the essentials... In the actual version there's
 error handling and whatnot):

 curl_easy_setopt(hCurl, CURLOPT_URL, adUrl);  // url to get the redirect
 location from
 curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, outUrl);
 curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, outUrlWrite);

 if(curl_easy_perform(hCurl) == 0)
 {
  apr_table_setn(r-headers_out, Location, outUrl);
 }

 r-content_type = CONTENT_TYPE_MOBILE;

 apr_table_setn(r-headers_out, Cache-Control, no-cache,
 must-revalidate);
 apr_table_setn(r-headers_out, Pragma, no-cache);

 curl_easy_cleanup(hCurl);

 return HTTP_MOVED_TEMPORARILY;


Use r-err_headers_out instead of r-headers_out. If it does not work,
there's a longer and more complicated solution based on
insert_error_filter. Come back for details if err_headers_out does not
solve the problem.

--
Sorin

-- 
A: Because it reverses the logical flow of conversation.
Q: Why is top-posting frowned upon?
A: Top-posting.
Q: What is the most annoying thing in e-mail?


Re: svn commit: r729579 - in /httpd/httpd/trunk: CHANGES modules/generators/mod_cgid.c

2009-01-06 Thread Jeff Trawick
On Sat, Dec 27, 2008 at 8:12 AM, Nick Kew n...@webthing.com wrote:


 On 27 Dec 2008, at 09:52, Ruediger Pluem wrote:



 On 12/27/2008 03:13 AM, n...@apache.org wrote:

 Author: niq
 Date: Fri Dec 26 18:13:47 2008
 New Revision: 729579

 URL: http://svn.apache.org/viewvc?rev=729579view=rev
 Log:
 PR#39332: fix for segfault problem with mod_cgid on Solaris
 Patch by Masaoki Kobayashi

 Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/generators/mod_cgid.c


 Just for my understanding. This patch works around a bug in Solaris with
 write
 and UNIX domain sockets, right?
 Otherwise I wouldn't get why the new code using writev would be better
 thatn the
 old one using write.


 It's a bug with a number of reports, though I haven't actually been able
 to reproduce it myself on opensolaris.


AFAIK it is resolved by 120664-01 or later (or x86-equiv patch), from
several years ago...


Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread Jeff Trawick
On Tue, Jan 6, 2009 at 10:05 AM, traw...@apache.org wrote:

 Author: trawick
 Date: Tue Jan  6 07:05:33 2009
 New Revision: 731965

 URL: http://svn.apache.org/viewvc?rev=731965view=rev
 Log:
 the length arguments are apr_size_t, not int

 Modified:
httpd/httpd/trunk/modules/generators/mod_cgid.c

 Modified: httpd/httpd/trunk/modules/generators/mod_cgid.c
 URL:
 http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/generators/mod_cgid.c?rev=731965r1=731964r2=731965view=diff

 ==
 --- httpd/httpd/trunk/modules/generators/mod_cgid.c (original)
 +++ httpd/httpd/trunk/modules/generators/mod_cgid.c Tue Jan  6 07:05:33
 2009
 @@ -354,7 +354,7 @@
 va_start(ap, count);
 for (i = 0; i  count; i++) {
 vec[i].iov_base = va_arg(ap, caddr_t);
 -vec[i].iov_len  = va_arg(ap, int);
 +vec[i].iov_len  = va_arg(ap, apr_size_t);


IIRC, size_t is 64-bit with a 64-bit build on AIX; someone with access to
the right bits (and bored out of their skull) could look for some fun
behavior with the original code


Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread Nick Kew

[crossposting because this httpd issue raises an APR issue]

Jeff Trawick wrote:
On Tue, Jan 6, 2009 at 10:05 AM, traw...@apache.org 
mailto:traw...@apache.org wrote:


Author: trawick
Date: Tue Jan  6 07:05:33 2009
New Revision: 731965

URL: http://svn.apache.org/viewvc?rev=731965view=rev
http://svn.apache.org/viewvc?rev=731965view=rev
Log:
the length arguments are apr_size_t, not int


How is it apr_size_t?

I see the following in apr_want.h.  Neither definition uses
apr_size_t.  man iovec shows int on Solaris, size_t on
FreeBSD and Linux.  Never AFAICS an apr_size_t.

apr_want.h contains the following, which appears to leave open
the possibility of not having it at all.  Do we have a deeper bug
here that calls for an apr_iovec datatype matching the platform?


#if APR_HAVE_IOVEC

#if APR_HAVE_SYS_UIO_H
#include sys/uio.h
#endif

#else

struct iovec
{
char *iov_base;
size_t iov_len;
};

#endif

--
Nick Kew


Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread William A. Rowe, Jr.
traw...@apache.org wrote:
 Author: trawick
 Date: Tue Jan  6 07:05:33 2009
 New Revision: 731965
 
 URL: http://svn.apache.org/viewvc?rev=731965view=rev
 Log:
 the length arguments are apr_size_t, not int
 
 Modified:
 httpd/httpd/trunk/modules/generators/mod_cgid.c
 
 Modified: httpd/httpd/trunk/modules/generators/mod_cgid.c
 URL: 
 http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/generators/mod_cgid.c?rev=731965r1=731964r2=731965view=diff
 ==
 --- httpd/httpd/trunk/modules/generators/mod_cgid.c (original)
 +++ httpd/httpd/trunk/modules/generators/mod_cgid.c Tue Jan  6 07:05:33 2009
 @@ -354,7 +354,7 @@
  va_start(ap, count);
  for (i = 0; i  count; i++) {
  vec[i].iov_base = va_arg(ap, caddr_t);
 -vec[i].iov_len  = va_arg(ap, int);
 +vec[i].iov_len  = va_arg(ap, apr_size_t);

More correctly, aren't these size_t native as opposed to apr_'s mapping?
This is a system structure, not an apr structure.



Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread Plüm, Rüdiger, VF-Group
 

 -Ursprüngliche Nachricht-
 Von: Nick Kew [mailto:n...@webthing.com] 
 Gesendet: Dienstag, 6. Januar 2009 16:48
 An: dev@httpd.apache.org; d...@apr.apache.org
 Betreff: Re: svn commit: r731965 - 
 /httpd/httpd/trunk/modules/generators/mod_cgid.c
 
 [crossposting because this httpd issue raises an APR issue]
 
 Jeff Trawick wrote:
  On Tue, Jan 6, 2009 at 10:05 AM, traw...@apache.org 
  mailto:traw...@apache.org wrote:
  
  Author: trawick
  Date: Tue Jan  6 07:05:33 2009
  New Revision: 731965
  
  URL: http://svn.apache.org/viewvc?rev=731965view=rev
  http://svn.apache.org/viewvc?rev=731965view=rev
  Log:
  the length arguments are apr_size_t, not int
 
 How is it apr_size_t?

I guess what is important here is that all length parameters passed to 
sock_writev as variable parameters are of size_t. So the second argument
given to va_arg should reflect this. IMHO it doesn't matter what type
we have in the iovec struct for this purpose.

Regards

Rüdiger



Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread Nick Kew

Plüm, Rüdiger, VF-Group wrote:

I guess what is important here is that all length parameters passed to 
sock_writev as variable parameters are of size_t. So the second argument

given to va_arg should reflect this. IMHO it doesn't matter what type
we have in the iovec struct for this purpose.


Sorry, yes, Jeff was right.  Looking at what gets passed to the
vararg-consuming function, that's apr_size_t.

Jeff, you have my +1 to add r731965 to my backport proposal in STATUS.

--
Nick Kew


Re: svn commit: r729579 - in /httpd/httpd/trunk: CHANGES modules/generators/mod_cgid.c

2009-01-06 Thread Justin Erenkrantz
On Tue, Jan 6, 2009 at 7:11 AM, Jeff Trawick traw...@gmail.com wrote:
 AFAIK it is resolved by 120664-01 or later (or x86-equiv patch), from
 several years ago...

Yah, we already have configure checks for this.  I don't like adding
unnecessary complexity to work around an OS bug that we've detected
and flagged for years.  -- justin


Re: svn commit: r731965 - /httpd/httpd/trunk/modules/generators/mod_cgid.c

2009-01-06 Thread William A. Rowe, Jr.
Nick Kew wrote:
 [crossposting because this httpd issue raises an APR issue]
 
 Jeff Trawick wrote:
 On Tue, Jan 6, 2009 at 10:05 AM, traw...@apache.org
 mailto:traw...@apache.org wrote:

 Author: trawick
 Date: Tue Jan  6 07:05:33 2009
 New Revision: 731965

 URL: http://svn.apache.org/viewvc?rev=731965view=rev
 http://svn.apache.org/viewvc?rev=731965view=rev
 Log:
 the length arguments are apr_size_t, not int
 
 How is it apr_size_t?
 
 I see the following in apr_want.h.  Neither definition uses
 apr_size_t.  man iovec shows int on Solaris, size_t on
 FreeBSD and Linux.  Never AFAICS an apr_size_t.
 
 apr_want.h contains the following, which appears to leave open
 the possibility of not having it at all.  Do we have a deeper bug
 here that calls for an apr_iovec datatype matching the platform?

Yes, I think we need an apr_iov_len_t type.

Bill


Graceful restart not so graceful?

2009-01-06 Thread William A. Rowe, Jr.
Would folks comment on Nathan's, Joe's and Stefan's work on

https://issues.apache.org/bugzilla/show_bug.cgi?id=42829

and offer any comments on why this patch;

https://issues.apache.org/bugzilla/attachment.cgi?id=22822

should not be applied to trunk/ and branches/2.2.x/ in time for
the next releases?

If I hear no objections by noon Jan 8 I'll apply.  According to
Stefan this current patch is improving the situation.

Bill



Re: svn commit: r729579 - in /httpd/httpd/trunk: CHANGES modules/generators/mod_cgid.c

2009-01-06 Thread Jeff Trawick
On Tue, Jan 6, 2009 at 11:28 AM, Justin Erenkrantz jus...@erenkrantz.comwrote:

 On Tue, Jan 6, 2009 at 7:11 AM, Jeff Trawick traw...@gmail.com wrote:
  AFAIK it is resolved by 120664-01 or later (or x86-equiv patch), from
  several years ago...

 Yah, we already have configure checks for this.  I don't like adding
 unnecessary complexity to work around an OS bug that we've detected
 and flagged for years.  -- justin


I'm happy to see some syscalls disappear, but this patch only goes so far.

-- 
Born in Roswell... married an alien...


Re: PR42829: graceful restart with multiple listeners using prefork MPM can result in hung processes

2009-01-06 Thread Jeff Trawick
On Tue, Feb 5, 2008 at 7:53 AM, Joe Orton jor...@redhat.com wrote:

 On Fri, Feb 01, 2008 at 10:41:39AM +0100, Stefan Fritsch wrote:
  Joe Orton wrote:
   I mentioned in the bug that the signal handler could cause undefined
   behaviour, but I'm not sure now whether that is true.  On Linux I can
   reproduce some cases where this will happen, which are all due to
   well-defined behaviour:
  
   1) with some (default on Linux) accept mutex types,
   apr_proc_mutex_lock() will loop on EINTR.  Hence, children blocked
   waiting for the mutex do hang until the mutex is released.  Fixing
   this would need some APR work, new interfaces, blah
 
  This is not a problem. On graceful-stop or reload the processes will get
  the lock one by one and die (or hang somewhere else). I have never seen a
  left over process hanging in this function.

 Well, normally all children will be woken up and take the accept mutex
 because of the dummy connections.  But if you have one child blocked
 because of issue (3) - whilst holding the accept mutex - all the other
 children will also be blocked.  If the EINTR could be processed at MPM
 level, this wouldn't happen.  So I think it is a problem, though you
 could argue that solving (3) also sort of solves (1).

   I can also reproduce a third case, but I'm not sure about the cause:
  
   3) apr_pollset_poll() is blocking despite the fact that the listening
   fds are supposedly already closed before entering the syscall.
 
  This is the main problem in my experience.
 ...
  On Linux with epoll, the hanging processes just blocks in
  apr_pollset_poll(), so checking the return value won't do any good.
 
  Maybe the problem is that (AIUI) poll() returns POLLNVAL if a fd is not
  open, while epoll() does not have something similar. In epoll.c, a
 comment
  says APR_POLLNVAL is not handled by epoll. Or should epoll return
  EPOLLHUP in this case?

 I did some more research on this: the case is covered in the epoll(7)
 man page - fds are removed from any containing epoll sets on closure.
 So it is well-defined behaviour, and the hang is expected; when all
 the listeners are closed, the poll set becomes empty, so the
 apr_pollset_poll() call will sleep forever, or until interrupted by
 signal!

 select() and poll() will indeed return POLLNVAL for the closed-fds case,
 and prefork needs to check for that.

 From some brief googling, FreeBSD kqueue appears to have the same
 guarantee.  This PR has some investigation of what happens with Solaris
 ports: http://issues.apache.org/bugzilla/show_bug.cgi?id=42580

 For the graceful-stop case, it would be simple enough to just signal any
 dozy children again to wake them up in the wait-for-exit loop, but
 graceful-restart doesn't have that opportunity, so I'm not sure about a
 general solution.  Reducing the poll timeout to some non-infinite time
 would work.


This holds up to some very light graceful-restart testing on OpenSolaris
(the same light testing that triggered a hang):

Index: server/mpm/prefork/prefork.c
===
--- server/mpm/prefork/prefork.c(revision 731724)
+++ server/mpm/prefork/prefork.c(working copy)
@@ -540,10 +540,12 @@
 apr_int32_t numdesc;
 const apr_pollfd_t *pdesc;

-/* timeout == -1 == wait forever */
-status = apr_pollset_poll(pollset, -1, numdesc, pdesc);
+/* timeout == 10 seconds to avoid a hang at graceful
restart/stop
+ * caused by the closing of sockets by the signal handler
+ */
+status = apr_pollset_poll(pollset, apr_time_from_sec(10),
numdesc, pdesc);
 if (status != APR_SUCCESS) {
-if (APR_STATUS_IS_EINTR(status)) {
+if (APR_STATUS_IS_TIMEUP(status) ||
APR_STATUS_IS_EINTR(status)) {
 if (one_process  shutdown_pending) {
 return;
 }


Re: Graceful restart not so graceful?

2009-01-06 Thread Jeff Trawick
On Tue, Jan 6, 2009 at 1:10 PM, William A. Rowe, Jr. wr...@rowe-clan.netwrote:

 Would folks comment on Nathan's, Joe's and Stefan's work on

 https://issues.apache.org/bugzilla/show_bug.cgi?id=42829

 and offer any comments on why this patch;

 https://issues.apache.org/bugzilla/attachment.cgi?id=22822

 should not be applied to trunk/ and branches/2.2.x/ in time for
 the next releases?

 If I hear no objections by noon Jan 8 I'll apply.  According to
 Stefan this current patch is improving the situation.

 Bill

 See also http://marc.info/?l=apache-httpd-devm=119945416529706w=2


Re: Graceful restart not so graceful?

2009-01-06 Thread Ruediger Pluem


On 01/06/2009 07:10 PM, William A. Rowe, Jr. wrote:
 Would folks comment on Nathan's, Joe's and Stefan's work on
 
 https://issues.apache.org/bugzilla/show_bug.cgi?id=42829
 
 and offer any comments on why this patch;
 
 https://issues.apache.org/bugzilla/attachment.cgi?id=22822
 
 should not be applied to trunk/ and branches/2.2.x/ in time for
 the next releases?

@@ -573,6 +588,11 @@ static void child_main(int child_num_arg
 apr_int32_t numdesc;
 const apr_pollfd_t *pdesc;

+if (die_now) {
+status = !APR_SUCCESS;
+goto unlock;
+}
+

Hm, what happens if we get the signal exactly here?
Then stop_listening only set die_now to 1. So we reenter the poll and stay in
until we get a new request to OUR process on one of the listeners.
Is this the desired behaviour?

 /* timeout == -1 == wait forever */
 status = apr_pollset_poll(pollset, -1, numdesc, pdesc);
 if (status != APR_SUCCESS) {

How about this one instead:

Index: server/mpm/prefork/prefork.c
===
--- server/mpm/prefork/prefork.c(Revision 731601)
+++ server/mpm/prefork/prefork.c(Arbeitskopie)
@@ -99,6 +99,8 @@
 static int mpm_state = AP_MPMQ_STARTING;
 static ap_pod_t *pod;

+static int dummy_listener;
+
 /*
  * The max child slot ever assigned, preserved across restarts.  Necessary
  * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts.  We
@@ -136,6 +138,8 @@
 #endif /* TPF */

 static volatile int die_now = 0;
+static volatile int listeners_closed = 0;
+static int close_connection = 1;

 #ifdef GPROF
 /*
@@ -304,8 +308,19 @@

 static void stop_listening(int sig)
 {
-ap_close_listeners();
+if (close_connection  !listeners_closed) {
+ap_listen_rec *lr;

+for (lr = ap_listeners; lr; lr = lr-next) {
+apr_os_sock_t fd;
+
+apr_os_sock_get(fd, lr-sd);
+
+dup2(dummy_listener, fd);
+}
+listeners_closed = 1;
+}
+
 /* For a graceful stop, we want the child to exit when done */
 die_now = 1;
 }
@@ -533,6 +548,7 @@
 if (num_listensocks == 1) {
 /* There is only one listener record, so refer to that one. */
 lr = ap_listeners;
+close_connection = 0;
 }
 else {
 /* multiple listening sockets - need to poll */
@@ -540,8 +556,14 @@
 apr_int32_t numdesc;
 const apr_pollfd_t *pdesc;

+if (die_now) {
+status = !APR_SUCCESS;
+goto unlock;
+}
+
 /* timeout == -1 == wait forever */
 status = apr_pollset_poll(pollset, -1, numdesc, pdesc);
+close_connection = 0;
 if (status != APR_SUCCESS) {
 if (APR_STATUS_IS_EINTR(status)) {
 if (one_process  shutdown_pending) {
@@ -595,8 +617,15 @@
 /* if we accept() something we don't want to die, so we have to
  * defer the exit
  */
-status = lr-accept_func(csd, lr, ptrans);
+if (!die_now) {
+status = lr-accept_func(csd, lr, ptrans);
+}
+else {
+status = !APR_SUCCESS;
+}

+unlock:
+close_connection = 1;
 SAFE_ACCEPT(accept_mutex_off());  /* unlock after accept */

 if (status == APR_EGENERAL) {
@@ -612,6 +641,11 @@
  * socket options, file descriptors, and read/write buffers.
  */

+if (die_now  !listeners_closed) {
+ap_close_listeners();
+listeners_closed = 1;
+}
+
 current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, 
my_child_num, sbh, bucket_alloc);
 if (current_conn) {
 ap_process_connection(current_conn, csd);
@@ -890,6 +924,17 @@
 mpm_state = AP_MPMQ_STOPPING;
 return 1;
 }
+
+if (dummy_listener == 0) {
+dummy_listener = socket(AF_INET, SOCK_STREAM, 0);
+if (dummy_listener  0) {
+rv = errno;
+ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
+ Couldn't create dummy listener socket);
+mpm_state = AP_MPMQ_STOPPING;
+return 1;
+}
+}

 #if APR_USE_SYSVSEM_SERIALIZE
 if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||



Regards

Rüdiger

Index: server/mpm/prefork/prefork.c
===
--- server/mpm/prefork/prefork.c	(Revision 731601)
+++ server/mpm/prefork/prefork.c	(Arbeitskopie)
@@ -99,6 +99,8 @@
 static int mpm_state = AP_MPMQ_STARTING;
 static ap_pod_t *pod;
 
+static int dummy_listener;
+
 /*
  * The max child slot ever assigned, preserved across restarts.  Necessary
  * to deal with MaxClients changes across AP_SIG_GRACEFUL