| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -25,6 +25,7 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "httpd.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "../cmn/mem.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "../cmn/syscall.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <qse/cmn/chr.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <qse/cmn/str.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <qse/cmn/mbwc.h>
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -627,67 +628,93 @@ httpd->cbs.on_error (httpd, l).... */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static int make_fd_set_from_client_array (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					qse_httpd_t* httpd, fd_set* r, fd_set* w, int for_rdwr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/* qse_http_loop() sets for_rdwr to true.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * response_thread() sets for_rdwr to false.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * qse_http_loop() 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *  - accepts a new client connection
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *  - reads a client request
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *  - writes back a response to a client request if not threaded.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * response_thread()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *  - writes back a response to a client request if threaded.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					int fd, max = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					client_array_t* ca = &httpd->client.array;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (r && for_rdwr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (for_rdwr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						/* qse_http_loop() needs to monitor listner handles
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 * to handle a new client connection. */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						max = httpd->listener.max;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						*r = httpd->listener.set;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (w)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					else 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						FD_ZERO (w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						FD_ZERO (r);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if defined(HAVE_PTHREAD)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						/* select() in response_thread() needs to be aborted
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 * if it's blocking on a fd_set previously composed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 * when a new task is enqueued. it can select() on new
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 * fd_set quickly.  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						QSE_ASSERT (httpd->threaded);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						FD_SET (httpd->client.pfd[0], r);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						max = httpd->client.pfd[0];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					FD_ZERO (w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (fd = 0; fd < ca->capa; fd++)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ca->data[fd].htrd) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (r && !ca->data[fd].bad) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (!ca->data[fd].bad) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (for_rdwr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/* add a client-side handle to the read set */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/* add a client-side handle to the read set
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * only for qse_httpd_loop(). */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									FD_SET (ca->data[fd].handle.i, r);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (ca->data[fd].task.queue.head && 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								    ca->data[fd].task.queue.head->task.trigger.i >= 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (!httpd->threaded || !for_rdwr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/* if a trigger is available, add it to the read set also */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									FD_SET (ca->data[fd].task.queue.head->task.trigger.i, r);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (ca->data[fd].task.queue.head->task.trigger.i > max) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										max = ca->data[fd].task.queue.head->task.trigger.i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/* a trigger is a handle to monitor to check
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * if there is data avaiable to write back to the client.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * if it is not threaded, qse_httpd_loop() needs to
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * monitor trigger handles. if it is threaded, 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * response_thread() needs to monitor these handles */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (ca->data[fd].task.queue.head && 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									    ca->data[fd].task.queue.head->task.trigger.i >= 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										/* if a trigger is available, add it to the read set also. */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										FD_SET (ca->data[fd].task.queue.head->task.trigger.i, r);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										if (ca->data[fd].task.queue.head->task.trigger.i > max) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											max = ca->data[fd].task.queue.head->task.trigger.i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if 0
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (w && (ca->data[fd].task.queue.count > 0 || ca->data[fd].bad))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (ca->data[fd].bad ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							    (ca->data[fd].task.queue.head && 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							     ca->data[fd].task.queue.head->task.trigger.i <= -1))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								/* add it to the set if it has a response to send */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								/* add a client-side handle to the write set 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * if the client is already marked bad or
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * the current task enqueued didn't specify a trigger.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * if the task doesn't have a trigger, i perform
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * the task so long as the client side-handle is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * available for writing in the main loop.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								FD_SET (ca->data[fd].handle.i, w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (w)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (ca->data[fd].bad ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								    (ca->data[fd].task.queue.head && 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								     ca->data[fd].task.queue.head->task.trigger.i <= -1))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/* add a client-side handle to the write set 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * if the client is already marked bad or
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * the current task enqueued didn't specify a trigger.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * if the task doesn't have a trigger, i perform
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * the task so long as the client side-handle is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 * available for writing in the main loop.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									FD_SET (ca->data[fd].handle.i, w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (ca->data[fd].handle.i > max) max = ca->data[fd].handle.i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -727,9 +754,6 @@ static void* response_thread (void* arg)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						fd_set r, w;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						struct timeval tv;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						tv.tv_sec = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						tv.tv_usec = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_mutex_lock (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						max = make_fd_set_from_client_array (httpd, &r, &w, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_mutex_unlock (&httpd->client.mutex);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -742,10 +766,11 @@ static void* response_thread (void* arg)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_mutex_lock (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							gettimeofday (&now, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							timeout.tv_sec = now.tv_sec + 2;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							timeout.tv_sec = now.tv_sec + 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							timeout.tv_nsec = now.tv_usec * 1000;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_cond_timedwait (&httpd->client.cond, &httpd->client.mutex, &timeout);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_cond_timedwait (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								&httpd->client.cond, &httpd->client.mutex, &timeout);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							max = make_fd_set_from_client_array (httpd, &r, &w, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_mutex_unlock (&httpd->client.mutex);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -753,6 +778,9 @@ static void* response_thread (void* arg)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (httpd->stopreq) break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						tv.tv_sec = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						tv.tv_usec = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						n = select (max + 1, &r, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (n <= -1)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -766,29 +794,18 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							continue;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (FD_ISSET (httpd->client.pfd[0], &r))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							qse_mchar_t dummy;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							QSE_READ (httpd->client.pfd[0], &dummy, 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for (fd = 0; fd < httpd->client.array.capa; fd++)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							qse_httpd_client_t* client = &httpd->client.array.data[fd];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (!client->htrd) continue;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							/* ---------------------------------------------- */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if 0
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (FD_ISSET(client->handle.i, &w)) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (client->bad) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								else if (client->task.queue.count > 0) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (client->task.queue.head->task.trigger.i <= -1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									    FD_ISSET(client->task.queue.head->task.trigger.i, &r))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										perform_task (httpd, client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (client->bad)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								/*shutdown (client->handle.i, SHUT_RDWR);*/
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -796,7 +813,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								delete_from_client_array (httpd, fd);     
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								pthread_mutex_unlock (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							else if (client->task.queue.head)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (client->task.queue.head->task.trigger.i <= -1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								    FD_ISSET(client->task.queue.head->task.trigger.i, &r))
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -805,12 +822,13 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure - %hs\n"), strerr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									tv.tv_usec = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									FD_ZERO (&w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									FD_SET (client->handle.i, &w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									n = select (max + 1, QSE_NULL, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									n = select (client->handle.i + 1, QSE_NULL, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (n > 0 && FD_ISSET(client->handle.i, &w)) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										perform_task (httpd, client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							/* ---------------------------------------------- */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -903,17 +921,30 @@ int qse_httpd_loop (qse_httpd_t* httpd, int threaded)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/* start the response sender as a thread */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (threaded)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_mutex_init (&httpd->client.mutex, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_cond_init (&httpd->client.cond, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (pthread_create (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							&response_thread_id, QSE_NULL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							response_thread, httpd) != 0) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (QSE_PIPE(httpd->client.pfd) == 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_cond_destroy (&httpd->client.cond);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_mutex_destroy (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							int i;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							for (i = 0; i < 2; i++)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								int flags = QSE_FCNTL (httpd->client.pfd[i], F_GETFD, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (flags >= 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									QSE_FCNTL (httpd->client.pfd[i], F_SETFD, flags | FD_CLOEXEC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_mutex_init (&httpd->client.mutex, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							pthread_cond_init (&httpd->client.cond, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (pthread_create (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								&response_thread_id, QSE_NULL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								response_thread, httpd) != 0) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								pthread_cond_destroy (&httpd->client.cond);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								pthread_mutex_destroy (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								QSE_CLOSE (httpd->client.pfd[1]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								QSE_CLOSE (httpd->client.pfd[0]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							else httpd->threaded = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						else httpd->threaded = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -935,7 +966,6 @@ int qse_httpd_loop (qse_httpd_t* httpd, int threaded)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (httpd->threaded) pthread_mutex_unlock (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						/*n = select (max + 1, &r, &w, QSE_NULL, &tv);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						n = select (max + 1, &r, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (n <= -1)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -984,31 +1014,6 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							/*----------------------------------------------------------*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if 0
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (!httpd->threaded && FD_ISSET(client->handle.i, &w)) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								/* output is handled in the main loop if and 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								 * only if it is not threaded */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (client->bad) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/*send (client->handle, i, "INTERNAL SERVER ERROR..", ...);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/*shutdown (client->handle.i, SHUT_RDWR);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/*pthread_mutex_lock (&httpd->client.mutex);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									delete_from_client_array (httpd, fd);     
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/*pthread_mutex_unlock (&httpd->client.mutex);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								else if (client->task.queue.count > 0) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (client->task.queue.head->task.trigger.i <= -1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									    FD_ISSET(client->task.queue.head->task.trigger.i, &r))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										perform_task (httpd, client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (!httpd->threaded)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if (client->bad)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -1018,7 +1023,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									delete_from_client_array (httpd, fd);     
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									/*pthread_mutex_unlock (&httpd->client.mutex);*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								else if (client->task.queue.count > 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								else if (client->task.queue.head)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if (client->task.queue.head->task.trigger.i <= -1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									    FD_ISSET(client->task.queue.head->task.trigger.i, &r))
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -1027,7 +1032,7 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										tv.tv_usec = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										FD_ZERO (&w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										FD_SET (client->handle.i, &w);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										n = select (max + 1, QSE_NULL, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										n = select (client->handle.i + 1, QSE_NULL, &w, QSE_NULL, &tv);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										/* TODO: logging if n == -1 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -1036,8 +1041,6 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							/*----------------------------------------------------------*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -1047,6 +1050,8 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_join (response_thread_id, QSE_NULL);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_cond_destroy (&httpd->client.cond);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_mutex_destroy (&httpd->client.mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						QSE_CLOSE (httpd->client.pfd[1]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						QSE_CLOSE (httpd->client.pfd[0]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -1287,7 +1292,15 @@ qse_httpd_task_t* qse_httpd_entask (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ret = enqueue_task_locked (httpd, client, pred, task, xtnsize);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (ret == QSE_NULL) client->bad = 1; /* mark this client bad */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if defined(HAVE_PTHREAD)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					else if (httpd->threaded) pthread_cond_signal (&httpd->client.cond);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					else if (httpd->threaded) 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						static qse_byte_t dummy = 0x01;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						/* write to the pipe to wake up select() in 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						 * the response thread if it was blocking. */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						QSE_WRITE (httpd->client.pfd[1], &dummy, 1); 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pthread_cond_signal (&httpd->client.cond);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |