#include "httpd.h"  
#include "http_config.h"  
#include "http_request.h"  
#include "http_protocol.h"  
#include "http_core.h"  
#include "http_main.h" 
#include "http_log.h"  
 
/* 
 * C version of chapter 9's Apache::SendFile
 * note: this does less than http_core.c:default_handler()
 * it is meant to be educational, and/or possibly a template
 * to alter behavior of default_handler()
 */ 

static int sendfile_handler(request_rec *r)
{
    int rc;
    FILE *f;

    if ((rc = ap_discard_request_body(r)) != OK) {
        return rc;
    }

    if (r->method_number == M_INVALID) {
	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
		    "Invalid method in request %s", r->the_request);
	return NOT_IMPLEMENTED;
    }
    if (r->method_number == M_OPTIONS) {
        return DECLINED;
    }
    if (r->method_number == M_PUT) {
        return METHOD_NOT_ALLOWED;
    }

    if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
	char *emsg;

	emsg = "File does not exist: ";
	if (r->path_info == NULL) {
	    emsg = ap_pstrcat(r->pool, emsg, r->filename, NULL);
	}
	else {
	    emsg = ap_pstrcat(r->pool, emsg, r->filename, r->path_info, NULL);
	}
	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, emsg);
	return HTTP_NOT_FOUND;
    }
    if (r->method_number != M_GET) {
        return METHOD_NOT_ALLOWED;
    }
	
#if defined(OS2) || defined(WIN32)
    /* Need binary mode for OS/2 */
    f = ap_pfopen(r->pool, r->filename, "rb");
#else
    f = ap_pfopen(r->pool, r->filename, "r");
#endif

    if (f == NULL) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
		     "file permissions deny server access: %s", r->filename);
        return FORBIDDEN;
    }
	
    ap_update_mtime(r, r->finfo.st_mtime);
    ap_set_last_modified(r);
    ap_set_etag(r);

    if (((rc = ap_meets_conditions(r)) != OK)
	|| (rc = ap_set_content_length(r, r->finfo.st_size))) {
        return rc;
    }

    ap_send_http_header(r);
	
    if (!r->header_only) {
	ap_send_fd(f, r);
    }

    ap_pfclose(r->pool, f);
    return OK;
}

static const handler_rec sendfile_handlers[] = { 
    { "*/*", sendfile_handler }, 
    { NULL }
};

module MODULE_VAR_EXPORT sendfile_module = {
    STANDARD_MODULE_STUFF, 
    NULL,                  /* module initializer                  */
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    sendfile_handlers,       /* [#8] MIME-typed-dispatched handlers */
    NULL,                  /* [#1] URI to filename translation    */
    NULL,                  /* [#4] validate user id from request  */
    NULL,                  /* [#5] check if the user is ok _here_ */
    NULL,                  /* [#3] check access by host address   */
    NULL,                  /* [#6] determine MIME type            */
    NULL,                  /* [#7] pre-run fixups                 */
    NULL,                  /* [#9] log a transaction              */
    NULL,                  /* [#2] header parser                  */
    NULL,                  /* child_init                          */
    NULL,                  /* child_exit                          */
    NULL                   /* [#0] post read-request              */
};

