~squid/squid/sbuf-use

« back to all changes in this revision

Viewing changes to src/client_side.cc

  • Committer: hno
  • Date: 2001-01-08 06:32:04 UTC
  • Revision ID: cvs-1:hno-20010108063204-w6a8e1zz6eprqnp8
Major rewrite of proxy authentication to support other schemes than
Basic (auth_rewrite branch on SourceForge).
Contributors:
   Andy Doran
   Robert Collins
   Chemolli Francesco
   Henrik Nordstrom

For details about the new API's, see Programmers Guide.

As part of this change everything from auth_modules has been moved to
src/auth/basic/helpers

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/*
3
 
 * $Id: client_side.cc,v 1.521 2001/01/05 09:51:36 adrian Exp $
 
3
 * $Id: client_side.cc,v 1.522 2001/01/07 23:36:37 hno Exp $
4
4
 *
5
5
 * DEBUG: section 33    Client-side Routines
6
6
 * AUTHOR: Duane Wessels
116
116
static log_type clientProcessRequest2(clientHttpRequest * http);
117
117
static int clientReplyBodyTooLarge(int clen);
118
118
static int clientRequestBodyTooLarge(int clen);
 
119
static void clientProcessBody(ConnStateData * conn);
119
120
 
120
121
static int
121
122
checkAccelOnly(clientHttpRequest * http)
138
139
clientIdentDone(const char *ident, void *data)
139
140
{
140
141
    ConnStateData *conn = data;
141
 
    if (ident)
142
 
        xstrncpy(conn->ident, ident, sizeof(conn->ident));
143
 
    else
144
 
        xstrncpy(conn->ident, "-", sizeof(conn->ident));
 
142
    xstrncpy(conn->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
145
143
}
 
144
 
146
145
#endif
147
146
 
148
147
static aclCheck_t *
152
151
    ConnStateData *conn = http->conn;
153
152
    ch = aclChecklistCreate(acl,
154
153
        http->request,
155
 
        conn->ident);
156
 
#if USE_IDENT
 
154
        conn->rfc931);
 
155
 
157
156
    /*
158
157
     * hack for ident ACL. It needs to get full addresses, and a
159
158
     * place to store the ident result on persistent connections...
160
159
     */
 
160
    /* connection oriented auth also needs these two lines for it's operation. */
161
161
    ch->conn = conn;
162
162
    cbdataLock(ch->conn);
163
 
#endif
 
163
 
164
164
    return ch;
165
165
}
166
166
 
223
223
        RequestMethodStr[http->request->method], http->uri,
224
224
        answer == ACCESS_ALLOWED ? "ALLOWED" : "DENIED",
225
225
        AclMatchedName ? AclMatchedName : "NO ACL's");
226
 
    if (http->acl_checklist->auth_user)
227
 
        proxy_auth_msg = http->acl_checklist->auth_user->message;
 
226
    proxy_auth_msg = authenticateAuthUserRequestMessage(http->conn->auth_user_request ? http->conn->auth_user_request : http->request->auth_user_request);
228
227
    http->acl_checklist = NULL;
229
228
    if (answer == ACCESS_ALLOWED) {
230
229
        safe_free(http->uri);
266
265
        err = errorCon(page_id, status);
267
266
        err->request = requestLink(http->request);
268
267
        err->src_addr = http->conn->peer.sin_addr;
269
 
        err->proxy_auth_msg = proxy_auth_msg;
 
268
        if (http->conn->auth_user_request)
 
269
            err->auth_user_request = http->conn->auth_user_request;
 
270
        else if (http->request->auth_user_request)
 
271
            err->auth_user_request = http->request->auth_user_request;
 
272
        /* lock for the error state */
 
273
        if (err->auth_user_request)
 
274
            authenticateAuthUserRequestLock(err->auth_user_request);
270
275
        err->callback_data = NULL;
271
276
        errorAppendEntry(http->entry, err);
272
277
    }
305
310
        new_request->my_addr = old_request->my_addr;
306
311
        new_request->my_port = old_request->my_port;
307
312
        new_request->flags.redirected = 1;
308
 
        if (old_request->user_ident[0])
309
 
            xstrncpy(new_request->user_ident, old_request->user_ident,
310
 
                USER_IDENT_SZ);
311
 
        if (old_request->body) {
312
 
            new_request->body = xmalloc(old_request->body_sz);
313
 
            xmemcpy(new_request->body, old_request->body, old_request->body_sz);
314
 
            new_request->body_sz = old_request->body_sz;
 
313
        new_request->auth_user_request = old_request->auth_user_request;
 
314
        if (old_request->body_connection) {
 
315
            new_request->body_connection = old_request->body_connection;
 
316
            old_request->body_connection = NULL;
315
317
        }
316
318
        new_request->content_length = old_request->content_length;
317
319
        new_request->flags.proxy_keepalive = old_request->flags.proxy_keepalive;
706
708
    MemObject *mem = NULL;
707
709
    debug(33, 3) ("httpRequestFree: %s\n", storeUrl(http->entry));
708
710
    if (!clientCheckTransferDone(http)) {
 
711
        if (request && request->body_connection)
 
712
            clientAbortBody(request);   /* abort body transter */
709
713
#if MYSTERIOUS_CODE
710
714
        /*
711
715
         * DW: this seems odd here, is it really needed?  It causes
746
750
            http->al.http.version = request->http_ver;
747
751
            http->al.headers.request = xstrdup(mb.buf);
748
752
            http->al.hier = request->hier;
749
 
            if (request->user_ident[0])
750
 
                http->al.cache.ident = request->user_ident;
751
 
            else
752
 
                http->al.cache.ident = conn->ident;
 
753
            if (request->auth_user_request) {
 
754
                http->al.cache.authuser = xstrdup(authenticateUserRequestUsername(request->auth_user_request));
 
755
                authenticateAuthUserRequestUnlock(request->auth_user_request);
 
756
                request->auth_user_request = NULL;
 
757
            }
 
758
            if (conn->rfc931[0])
 
759
                http->al.cache.rfc931 = conn->rfc931;
753
760
            packerClean(&p);
754
761
            memBufClean(&mb);
755
762
        }
784
791
    requestUnlink(http->request);
785
792
    assert(http != http->next);
786
793
    assert(http->conn->chr != NULL);
 
794
    /* Unlink us from the clients request list */
787
795
    H = &http->conn->chr;
788
796
    while (*H) {
789
797
        if (*H == http)
805
813
    clientHttpRequest *http;
806
814
    debug(33, 3) ("connStateFree: FD %d\n", fd);
807
815
    assert(connState != NULL);
 
816
    authenticateOnCloseConnection(connState);
808
817
    clientdbEstablished(connState->peer.sin_addr, -1);  /* decrement */
809
818
    while ((http = connState->chr) != NULL) {
810
819
        assert(http->conn == connState);
986
995
    if (req->protocol == PROTO_HTTP)
987
996
        return httpCachable(method);
988
997
    /* FTP is always cachable */
989
 
    if (req->protocol == PROTO_GOPHER)
990
 
        return gopherCachable(url);
991
998
    if (req->protocol == PROTO_WAIS)
992
999
        return 0;
993
1000
    if (method == METHOD_CONNECT)
994
1001
        return 0;
995
1002
    if (method == METHOD_TRACE)
996
1003
        return 0;
 
1004
    if (method == METHOD_PUT)
 
1005
        return 0;
 
1006
    if (method == METHOD_POST)
 
1007
        return 0;               /* XXX POST may be cached sometimes.. ignored for now */
 
1008
    if (req->protocol == PROTO_GOPHER)
 
1009
        return gopherCachable(url);
997
1010
    if (req->protocol == PROTO_CACHEOBJ)
998
1011
        return 0;
999
1012
    return 1;
1272
1285
                httpHeaderPutInt(hdr, HDR_AGE,
1273
1286
                    squid_curtime - http->entry->timestamp);
1274
1287
    }
 
1288
    /* Handle authentication headers */
 
1289
    if (request->auth_user_request)
 
1290
        authenticateFixHeader(rep, request->auth_user_request, request, http->flags.accel);
1275
1291
    /* Append X-Cache */
1276
1292
    httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
1277
1293
        is_hit ? "HIT" : "MISS", getMyHostname());
1853
1869
    if ((http = conn->chr) == NULL) {
1854
1870
        debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next req\n",
1855
1871
            conn->fd);
1856
 
        fd_note(conn->fd, "Reading next request");
 
1872
        fd_note(conn->fd, "Waiting for next request");
1857
1873
        /*
1858
1874
         * Set the timeout BEFORE calling clientReadRequest().
1859
1875
         */
2135
2151
        }
2136
2152
        /* yes, continue */
2137
2153
        http->log_type = LOG_TCP_MISS;
2138
 
    } else if (r->content_length >= 0) {
2139
 
        /*
2140
 
         * Need to initialize pump even if content-length: 0
2141
 
         */
2142
 
        http->log_type = LOG_TCP_MISS;
2143
 
        /* XXX oof, POST can be cached! */
2144
 
        pumpInit(fd, r, http->uri);
2145
2154
    } else {
2146
2155
        http->log_type = clientProcessRequest2(http);
2147
2156
    }
2509
2518
clientReadDefer(int fdnotused, void *data)
2510
2519
{
2511
2520
    ConnStateData *conn = data;
2512
 
    return conn->defer.until > squid_curtime;
 
2521
    if (conn->body.size_left)
 
2522
        return conn->in.offset >= conn->in.size;
 
2523
    else
 
2524
        return conn->defer.until > squid_curtime;
2513
2525
}
2514
2526
 
2515
2527
static void
2542
2554
     * whole, not individual read() calls.  Plus, it breaks our
2543
2555
     * lame half-close detection
2544
2556
     */
2545
 
    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
2546
 
    if (size == 0) {
2547
 
        if (conn->chr == NULL) {
 
2557
    if (size > 0) {
 
2558
        conn->in.offset += size;
 
2559
        conn->in.buf[conn->in.offset] = '\0';   /* Terminate the string */
 
2560
    } else if (size == 0 && len > 0) {
 
2561
        if (conn->chr == NULL && conn->in.offset == 0) {
2548
2562
            /* no current or pending requests */
 
2563
            debug(33, 4) ("clientReadRequest: FD %d closed\n", fd);
2549
2564
            comm_close(fd);
2550
2565
            return;
2551
2566
        } else if (!Config.onoff.half_closed_clients) {
2552
2567
            /* admin doesn't want to support half-closed client sockets */
 
2568
            debug(33, 3) ("clientReadRequest: FD %d aborted (half_closed_clients disabled)\n", fd);
2553
2569
            comm_close(fd);
2554
2570
            return;
2555
2571
        }
2559
2575
        conn->defer.until = squid_curtime + 1;
2560
2576
        conn->defer.n++;
2561
2577
        fd_note(fd, "half-closed");
2562
 
        return;
 
2578
        /* There is one more close check at the end, to detect aborted
 
2579
         * (partial) requests. At this point we can't tell if the request
 
2580
         * is partial.
 
2581
         */
 
2582
        /* Continue to process previously read data */
2563
2583
    } else if (size < 0) {
2564
2584
        if (!ignoreErrno(errno)) {
2565
2585
            debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror());
2570
2590
            return;
2571
2591
        }
2572
2592
        /* Continue to process previously read data */
2573
 
        size = 0;
2574
2593
    }
2575
 
    conn->in.offset += size;
2576
 
    /* Skip leading (and trailing) whitespace */
2577
 
    while (conn->in.offset > 0) {
 
2594
    commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
 
2595
    /* Process request body if any */
 
2596
    if (conn->in.offset > 0 && conn->body.callback != NULL)
 
2597
        clientProcessBody(conn);
 
2598
    /* Process next request */
 
2599
    while (conn->in.offset > 0 && conn->body.size_left == 0) {
2578
2600
        int nrequests;
2579
2601
        size_t req_line_sz;
 
2602
        /* Skip leading (and trailing) whitespace */
2580
2603
        while (conn->in.offset > 0 && xisspace(conn->in.buf[0])) {
2581
2604
            xmemmove(conn->in.buf, conn->in.buf + 1, conn->in.offset - 1);
2582
2605
            conn->in.offset--;
2592
2615
            conn->defer.until = squid_curtime + 100;    /* Reset when a request is complete */
2593
2616
            break;
2594
2617
        }
 
2618
        conn->in.buf[conn->in.offset] = '\0';   /* Terminate the string */
 
2619
        if (nrequests == 0)
 
2620
            fd_note(conn->fd, "Reading next request");
2595
2621
        /* Process request */
2596
2622
        http = parseHttpRequest(conn,
2597
2623
            &method,
2686
2712
                errorAppendEntry(http->entry, err);
2687
2713
                break;
2688
2714
            }
2689
 
            if (0 == clientCheckContentLength(request)) {
 
2715
            if (!clientCheckContentLength(request)) {
2690
2716
                err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
2691
2717
                err->src_addr = conn->peer.sin_addr;
2692
2718
                err->request = requestLink(request);
2696
2722
                break;
2697
2723
            }
2698
2724
            http->request = requestLink(request);
2699
 
            /*
2700
 
             * We need to set the keepalive flag before doing some
2701
 
             * hacks for POST/PUT requests below.  Maybe we could
2702
 
             * set keepalive flag even earlier.
2703
 
             */
2704
2725
            clientSetKeepaliveFlag(http);
2705
 
            /*
2706
 
             * break here if the request has a content-length
2707
 
             * because there is a reqeust body following and we
2708
 
             * don't want to parse it as though it was new request.
2709
 
             */
2710
 
            if (request->content_length >= 0) {
2711
 
                int copy_len = XMIN(conn->in.offset, request->content_length);
2712
 
                if (copy_len > 0) {
2713
 
                    assert(conn->in.offset >= copy_len);
2714
 
                    request->body_sz = copy_len;
2715
 
                    request->body = xmalloc(request->body_sz);
2716
 
                    xmemcpy(request->body, conn->in.buf, request->body_sz);
2717
 
                    conn->in.offset -= copy_len;
2718
 
                    if (conn->in.offset)
2719
 
                        xmemmove(conn->in.buf, conn->in.buf + copy_len, conn->in.offset);
2720
 
                }
2721
 
                /*
2722
 
                 * if we didn't get the full body now, then more will
2723
 
                 * be arriving on the client socket.  Lets cancel
2724
 
                 * the read handler until this request gets forwarded.
2725
 
                 */
2726
 
                if (request->body_sz < request->content_length)
2727
 
                    commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
2728
 
                if (request->content_length < 0)
2729
 
                    (void) 0;
2730
 
                else if (clientRequestBodyTooLarge(request->content_length)) {
 
2726
            /* Do we expect a request-body? */
 
2727
            if (request->content_length > 0) {
 
2728
                conn->body.size_left = request->content_length;
 
2729
                request->body_connection = conn;
 
2730
                /* Is it too large? */
 
2731
                if (clientRequestBodyTooLarge(request->content_length)) {
2731
2732
                    err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
2732
2733
                    err->request = requestLink(request);
2733
2734
                    http->entry = clientCreateStoreEntry(http,
2737
2738
                }
2738
2739
            }
2739
2740
            clientAccessCheck(http);
2740
 
            continue;           /* while offset > 0 */
 
2741
            continue;           /* while offset > 0 && body.size_left == 0 */
2741
2742
        } else if (parser_return_code == 0) {
2742
2743
            /*
2743
2744
             *    Partial request received; reschedule until parseHttpRequest()
2776
2777
            }
2777
2778
            break;
2778
2779
        }
2779
 
    }
 
2780
    }                           /* while offset > 0 && conn->body.size_left == 0 */
 
2781
    /* Check if a half-closed connection was aborted in the middle */
 
2782
    if (F->flags.socket_eof) {
 
2783
        if (conn->in.offset != conn->body.size_left) {  /* != 0 when no request body */
 
2784
            /* Partial request received. Abort client connection! */
 
2785
            debug(33, 3) ("clientReadRequest: FD %d aborted\n", fd);
 
2786
            comm_close(fd);
 
2787
            return;
 
2788
        }
 
2789
    }
 
2790
}
 
2791
 
 
2792
/* file_read like function, for reading body content */
 
2793
void
 
2794
clientReadBody(request_t * request, char *buf, size_t size, CBCB * callback, void *cbdata)
 
2795
{
 
2796
    ConnStateData *conn = request->body_connection;
 
2797
    if (!conn) {
 
2798
        debug(33, 5) ("clientReadBody: no body to read, request=%p\n", request);
 
2799
        callback(buf, 0, cbdata);       /* Signal end of body */
 
2800
        return;
 
2801
    }
 
2802
    debug(33, 2) ("clientReadBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
 
2803
    conn->body.callback = callback;
 
2804
    conn->body.cbdata = cbdata;
 
2805
    conn->body.buf = buf;
 
2806
    conn->body.bufsize = size;
 
2807
    conn->body.request = requestLink(request);
 
2808
    if (conn->in.offset) {
 
2809
        /* Data available */
 
2810
        clientProcessBody(conn);
 
2811
    } else {
 
2812
        debug(33, 2) ("clientReadBody: fd %d wait for clientReadRequest\n", conn->fd);
 
2813
    }
 
2814
}
 
2815
 
 
2816
/* Called by clientReadRequest to process body content */
 
2817
static void
 
2818
clientProcessBody(ConnStateData * conn)
 
2819
{
 
2820
    int size;
 
2821
    char *buf = conn->body.buf;
 
2822
    void *cbdata = conn->body.cbdata;
 
2823
    CBCB *callback = conn->body.callback;
 
2824
    request_t *request = conn->body.request;
 
2825
    /* Note: request is null while eating "aborted" transfers */
 
2826
    debug(33, 2) ("clientProcessBody: start fd=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, conn->body.size_left, conn->in.offset, callback, request);
 
2827
    /* Some sanity checks... */
 
2828
    assert(conn->body.size_left > 0);
 
2829
    assert(conn->in.offset > 0);
 
2830
    assert(callback != NULL);
 
2831
    assert(buf != NULL);
 
2832
    /* How much do we have to process? */
 
2833
    size = conn->in.offset;
 
2834
    if (size > conn->body.size_left)    /* only process the body part */
 
2835
        size = conn->body.size_left;
 
2836
    if (size > conn->body.bufsize)      /* don't copy more than requested */
 
2837
        size = conn->body.bufsize;
 
2838
    xmemcpy(buf, conn->in.buf, size);
 
2839
    conn->body.size_left -= size;
 
2840
    /* Move any remaining data */
 
2841
    conn->in.offset -= size;
 
2842
    if (conn->in.offset > 0)
 
2843
        xmemmove(conn->in.buf, conn->in.buf + size, conn->in.offset);
 
2844
    /* Remove request link if this is the last part of the body, as
 
2845
     * clientReadRequest automatically continues to process next request */
 
2846
    if (conn->body.size_left <= 0 && request != NULL)
 
2847
        request->body_connection = NULL;
 
2848
    /* Remove clientReadBody arguments (the call is completed) */
 
2849
    conn->body.request = NULL;
 
2850
    conn->body.callback = NULL;
 
2851
    conn->body.buf = NULL;
 
2852
    conn->body.bufsize = 0;
 
2853
    /* Remember that we have touched the body, not restartable */
 
2854
    if (request != NULL)
 
2855
        request->flags.body_sent = 1;
 
2856
    /* Invoke callback function */
 
2857
    callback(buf, size, cbdata);
 
2858
    if (request != NULL)
 
2859
        requestUnlink(request); /* Linked in clientReadBody */
 
2860
    debug(33, 2) ("clientProcessBody: end fd=%d size=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, size, conn->body.size_left, conn->in.offset, callback, request);
 
2861
    return;
 
2862
}
 
2863
 
 
2864
/* A dummy handler that throws away a request-body */
 
2865
static char bodyAbortBuf[SQUID_TCP_SO_RCVBUF];
 
2866
void
 
2867
clientReadBodyAbortHandler(char *buf, size_t size, void *data)
 
2868
{
 
2869
    ConnStateData *conn = (ConnStateData *) data;
 
2870
    debug(33, 2) ("clientReadBodyAbortHandler: fd=%d body_size=%d in.offset=%d\n", conn->fd, conn->body.size_left, conn->in.offset);
 
2871
    if (size != 0 && conn->body.size_left != 0) {
 
2872
        debug(33, 3) ("clientReadBodyAbortHandler: fd=%d shedule next read\n", conn->fd);
 
2873
        conn->body.callback = clientReadBodyAbortHandler;
 
2874
        conn->body.buf = bodyAbortBuf;
 
2875
        conn->body.bufsize = sizeof(bodyAbortBuf);
 
2876
        conn->body.cbdata = data;
 
2877
    }
 
2878
}
 
2879
 
 
2880
/* Abort a body request */
 
2881
int
 
2882
clientAbortBody(request_t * request)
 
2883
{
 
2884
    ConnStateData *conn = request->body_connection;
 
2885
    char *buf;
 
2886
    CBCB *callback;
 
2887
    void *cbdata;
 
2888
    request->body_connection = NULL;
 
2889
    if (!conn || conn->body.size_left <= 0)
 
2890
        return 0;               /* No body to abort */
 
2891
    if (conn->body.callback != NULL) {
 
2892
        buf = conn->body.buf;
 
2893
        callback = conn->body.callback;
 
2894
        cbdata = conn->body.cbdata;
 
2895
        assert(request == conn->body.request);
 
2896
        conn->body.buf = NULL;
 
2897
        conn->body.callback = NULL;
 
2898
        conn->body.cbdata = NULL;
 
2899
        conn->body.request = NULL;
 
2900
        callback(buf, -1, cbdata);      /* Signal abort to clientReadBody caller */
 
2901
        requestUnlink(request);
 
2902
    }
 
2903
    clientReadBodyAbortHandler(NULL, -1, conn);         /* Install abort handler */
 
2904
    /* clientProcessBody() */
 
2905
    return 1;                   /* Aborted */
2780
2906
}
2781
2907
 
2782
2908
/* general lifetime handler for HTTP requests */