Bug Summary

File:d/conn.c
Warning:line 1211, column 5
Duplicate code detected
Note:line 1212, column 5
Similar code here

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name conn.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsd -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsd -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c conn.c
1/*
2 * The contents of this file are subject to the Mozilla Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://www.mozilla.org/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30
31/*
32 * conn.c --
33 *
34 * Manage the Ns_Conn structure
35 */
36
37#include "nsd.h"
38
39static Ns_ObjvValueRange posintRange0 = {0, INT_MAX2147483647};
40static Ns_ObjvValueRange posintRange1 = {1, INT_MAX2147483647};
41
42/*
43 * Static functions defined in this file.
44 */
45
46static int GetChan(Tcl_Interp *interp, const char *id, Tcl_Channel *chanPtr)
47 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))) NS_GNUC_NONNULL(3)__attribute__((__nonnull__(3)));
48
49static Tcl_Channel MakeConnChannel(const NsInterp *itPtr, Ns_Conn *conn)
50 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2)));
51
52static const Ns_Driver* ConnGetDriver(const Ns_Conn *conn) NS_GNUC_PURE
53 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1)));
54
55
56/*
57 *----------------------------------------------------------------------
58 *
59 * Ns_ConnHeaders --
60 *
61 * Get the headers
62 *
63 * Results:
64 * An Ns_Set containing HTTP headers from the client
65 *
66 * Side effects:
67 * None
68 *
69 *----------------------------------------------------------------------
70 */
71
72Ns_Set *
73Ns_ConnHeaders(const Ns_Conn *conn)
74{
75 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
76 return conn->headers;
77}
78
79
80/*
81 *----------------------------------------------------------------------
82 *
83 * Ns_ConnOutputHeaders --
84 *
85 * Get the output headers
86 *
87 * Results:
88 * A writable Ns_Set containing headers to send back to the client
89 *
90 * Side effects:
91 * None
92 *
93 *----------------------------------------------------------------------
94 */
95
96Ns_Set *
97Ns_ConnOutputHeaders(const Ns_Conn *conn)
98{
99 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
100 return conn->outputheaders;
101}
102
103/*
104 *----------------------------------------------------------------------
105 *
106 * Ns_ConnAuth --
107 *
108 * Get the authentication headers
109 *
110 * Results:
111 * An Ns_Set containing authentication user/password and other parameters
112 * as in digest method
113 *
114 * Side effects:
115 * None
116 *
117 *----------------------------------------------------------------------
118 */
119
120Ns_Set *
121Ns_ConnAuth(const Ns_Conn *conn)
122{
123 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
124 return conn->auth;
125}
126
127
128/*
129 *----------------------------------------------------------------------
130 *
131 * Ns_ConnAuthUser --
132 *
133 * Get the authenticated user
134 *
135 * Results:
136 * A pointer to a string with the username
137 *
138 * Side effects:
139 * None
140 *
141 *----------------------------------------------------------------------
142 */
143
144const char *
145Ns_ConnAuthUser(const Ns_Conn *conn)
146{
147 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
148 return (conn->auth != NULL((void*)0)) ? Ns_SetIGet(conn->auth, "Username") : NULL((void*)0);
149}
150
151
152/*
153 *----------------------------------------------------------------------
154 *
155 * Ns_ConnAuthPasswd --
156 *
157 * Get the authenticated user's password
158 *
159 * Results:
160 * A pointer to a string with the user's plaintext password
161 *
162 * Side effects:
163 * None
164 *
165 *----------------------------------------------------------------------
166 */
167
168const char *
169Ns_ConnAuthPasswd(const Ns_Conn *conn)
170{
171 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
172 return (conn->auth != NULL((void*)0)) ? Ns_SetIGet(conn->auth, "Password") : NULL((void*)0);
173}
174
175
176/*
177 *----------------------------------------------------------------------
178 *
179 * Ns_ConnContentLength --
180 *
181 * Get the content length from the client
182 *
183 * Results:
184 * A size_t content length, or 0u if no data was sent
185 *
186 * Side effects:
187 * None
188 *
189 *----------------------------------------------------------------------
190 */
191
192size_t
193Ns_ConnContentLength(const Ns_Conn *conn)
194{
195 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
196 return conn->contentLength;
197}
198
199
200/*
201 *----------------------------------------------------------------------
202 *
203 * Ns_ConnContent --
204 *
205 * Return pointer to start of content.
206 *
207 * Results:
208 * Start of content.
209 *
210 * Side effects:
211 * None
212 *
213 *----------------------------------------------------------------------
214 */
215
216const char *
217Ns_ConnContent(const Ns_Conn *conn)
218{
219 const Conn *connPtr = (const Conn *) conn;
220
221 return connPtr->reqPtr->content;
222}
223
224/*
225 *----------------------------------------------------------------------
226 *
227 * Ns_ConnContentSize --
228 *
229 * Return size of the posted content.
230 *
231 * Results:
232 * Size of the content buffer
233 *
234 * Side effects:
235 * None
236 *
237 *----------------------------------------------------------------------
238 */
239
240size_t
241Ns_ConnContentSize(const Ns_Conn *conn)
242{
243 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
244
245 return ((const Conn *)conn)->reqPtr->length;
246}
247
248/*
249 *----------------------------------------------------------------------
250 *
251 * Ns_ConnContentFile --
252 *
253 * Return pointer of the filename with spooled content.
254 *
255 * Results:
256 * Pointer to string
257 *
258 * Side effects:
259 * None
260 *
261 *----------------------------------------------------------------------
262 */
263
264const char *
265Ns_ConnContentFile(const Ns_Conn *conn)
266{
267 const Sock *sockPtr;
268
269 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
270
271 sockPtr = ((const Conn *)conn)->sockPtr;
272 return (sockPtr != NULL((void*)0)) ? sockPtr->tfile : NULL((void*)0);
273}
274
275/*
276 *----------------------------------------------------------------------
277 *
278 * Ns_ConnContentFd --
279 *
280 * Return opened file descriptor of the file with spooled content.
281 *
282 * Results:
283 * File descriptor or 0 if not used
284 *
285 * Side effects:
286 * None
287 *
288 *----------------------------------------------------------------------
289 */
290
291int
292Ns_ConnContentFd(const Ns_Conn *conn)
293{
294 const Sock *sockPtr;
295
296 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
297
298 sockPtr = ((const Conn *)conn)->sockPtr;
299
300 return (sockPtr != NULL((void*)0)) ? sockPtr->tfd : 0;
301}
302
303
304/*
305 *----------------------------------------------------------------------
306 *
307 * Ns_ConnServer --
308 *
309 * Get the server name
310 *
311 * Results:
312 * A string ptr to the server name
313 *
314 * Side effects:
315 * None
316 *
317 *----------------------------------------------------------------------
318 */
319
320const char *
321Ns_ConnServer(const Ns_Conn *conn)
322{
323 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
324
325 return ((const Conn *)conn)->server;
326}
327
328
329/*
330 *----------------------------------------------------------------------
331 *
332 * Ns_ConnResponseStatus, Ns_ConnSetResponseStatus --
333 *
334 * Get (set) the HTTP response code that will be sent.
335 *
336 * Results:
337 * An integer response code (e.g., 200 for OK).
338 *
339 * Side effects:
340 * NB: Status 200 is the default and can not be set manually.
341 *
342 *----------------------------------------------------------------------
343 */
344
345int
346Ns_ConnResponseStatus(const Ns_Conn *conn)
347{
348 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
349
350 return ((const Conn *)conn)->responseStatus;
351
352}
353
354void
355Ns_ConnSetResponseStatus(Ns_Conn *conn, int newStatus)
356{
357 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
358
359 if (newStatus != 200) {
360 ((Conn *)conn)->responseStatus = newStatus;
361 }
362}
363
364
365/*
366 *----------------------------------------------------------------------
367 *
368 * Ns_ConnContentSent --
369 *
370 * Return the number of bytes sent to the browser after headers
371 *
372 * Results:
373 * Bytes sent
374 *
375 * Side effects:
376 * None
377 *
378 *----------------------------------------------------------------------
379 */
380
381size_t
382Ns_ConnContentSent(const Ns_Conn *conn)
383{
384 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
385
386 return ((const Conn *)conn)->nContentSent;
387}
388
389/*
390 *----------------------------------------------------------------------
391 *
392 * Ns_ConnSetContentSent --
393 *
394 * Set the number of bytes sent to the browser after headers
395 *
396 * Results:
397 * None
398 *
399 * Side effects:
400 * None
401 *
402 *----------------------------------------------------------------------
403 */
404
405void
406Ns_ConnSetContentSent(Ns_Conn *conn, size_t length)
407{
408 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
409
410 ((Conn *)conn)->nContentSent = length;
411}
412
413
414/*
415 *----------------------------------------------------------------------
416 *
417 * Ns_ConnResponseLength --
418 *
419 * Get the response length
420 *
421 * Results:
422 * Integer, number of bytes to send
423 *
424 * Side effects:
425 * None
426 *
427 *----------------------------------------------------------------------
428 */
429
430ssize_t
431Ns_ConnResponseLength(const Ns_Conn *conn)
432{
433 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
434
435 return ((const Conn *)conn)->responseLength;
436}
437
438
439/*
440 *----------------------------------------------------------------------
441 *
442 * Ns_ConnPeerAddr, Ns_ConnForwardedPeerAddr --
443 *
444 * Get the peer's direct or forwarded IP address.
445 * The forwarded IP address is determined by the
446 * X-Forwarded-For header.
447 *
448 * Results:
449 * A string IP address
450 *
451 * Side effects:
452 * None
453 *
454 *----------------------------------------------------------------------
455 */
456
457const char *
458Ns_ConnPeerAddr(const Ns_Conn *conn)
459{
460 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
461
462 return ((const Conn *)conn)->peer;
463}
464
465const char *
466Ns_ConnForwardedPeerAddr(const Ns_Conn *conn)
467{
468 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
469
470 return ((const Conn *)conn)->proxypeer;
471}
472
473/*
474 *----------------------------------------------------------------------
475 *
476 * Ns_ConnPeerAddr, Ns_ConnForwardedPeerAddr --
477 *
478 * This is a mode specifoc function for determining the IP address of the
479 * communication peer. In reverse proxy mode, try to get the forwarded IP
480 * address. In case, this fails, return the direct IP address. When
481 * reverse proxy mode is turned off, return the direct IP address.
482 *
483 * Results:
484 * A string IP address
485 *
486 * Side effects:
487 * None
488 *
489 *----------------------------------------------------------------------
490 */
491const char *
492Ns_ConnConfiguredPeerAddr(const Ns_Conn *conn)
493{
494 const char *p;
495
496 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
497
498 if (nsconf.reverseproxymode) {
499 p = Ns_ConnForwardedPeerAddr(conn);
500 if (*p == '\0') {
501 p = Ns_ConnPeerAddr(conn);
502 }
503 } else {
504 p = Ns_ConnPeerAddr(conn);
505 }
506 return p;
507}
508
509/*
510 *----------------------------------------------------------------------
511 *
512 * Ns_ConnCurrentAddr --
513 *
514 * Get the local IP address of the current connection
515 *
516 * Results:
517 * A string IP address or NULL
518 *
519 * Side effects:
520 * None
521 *
522 *----------------------------------------------------------------------
523 */
524const char *
525Ns_ConnCurrentAddr(const Ns_Conn *conn)
526{
527 const char *result;
528 const Conn *connPtr;
529
530 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
531
532 connPtr = (Conn *)conn;
533 if (connPtr->sockPtr != NULL((void*)0)) {
534 result = Ns_SockGetAddr((Ns_Sock *)connPtr->sockPtr);
535 } else {
536 result = NULL((void*)0);
537 }
538 return result;
539}
540
541
542/*
543 *----------------------------------------------------------------------
544 *
545 * Ns_ConnCurrentPort --
546 *
547 * Get the local port of the current connection
548 *
549 * Results:
550 * port or 0 when operation fails
551 *
552 * Side effects:
553 * None
554 *
555 *----------------------------------------------------------------------
556 */
557unsigned short
558Ns_ConnCurrentPort(const Ns_Conn *conn)
559{
560 unsigned short result;
561 const Conn *connPtr;
562
563 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
564
565 connPtr = (const Conn *)conn;
566 if (connPtr->sockPtr != NULL((void*)0)) {
567 result = Ns_SockGetPort((Ns_Sock *)(connPtr->sockPtr));
568 } else {
569 result = 0u;
570 }
571 return result;
572}
573
574/*
575 *----------------------------------------------------------------------
576 *
577 * Ns_ConnPeer --
578 *
579 * Get the peer's internet address, deprecated version of
580 * Ns_ConnPeerAddr().
581 *
582 * Deprecated: Use Ns_ConnPeerAddr() for naming symmetry with
583 * the variants without "Peer" in the name.
584 *
585 * Results:
586 * A string IP address
587 *
588 * Side effects:
589 * None
590 *
591 *----------------------------------------------------------------------
592 */
593
594const char *
595Ns_ConnPeer(const Ns_Conn *conn)
596{
597 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
598
599 return Ns_ConnPeerAddr(conn);
600}
601
602/*
603 *----------------------------------------------------------------------
604 *
605 * Ns_ConnSetPeer --
606 *
607 * Set the peer's internet address and port
608 *
609 * Results:
610 * A string IP address
611 *
612 * Side effects:
613 * None
614 *
615 *----------------------------------------------------------------------
616 */
617
618const char *
619Ns_ConnSetPeer(const Ns_Conn *conn, const struct sockaddr *saPtr, const struct sockaddr *clientsaPtr)
620{
621 Conn *connPtr;
622
623 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
624 NS_NONNULL_ASSERT(saPtr != NULL)((void) (0));
625 NS_NONNULL_ASSERT(clientsaPtr != NULL)((void) (0));
626
627 connPtr = (Conn *)conn;
628
629 connPtr->reqPtr->port = Ns_SockaddrGetPort(saPtr);
630 (void)ns_inet_ntop(saPtr, connPtr->peer, NS_IPADDR_SIZE46);
631
632 if (clientsaPtr->sa_family != 0) {
633 (void)ns_inet_ntop(clientsaPtr, connPtr->proxypeer, NS_IPADDR_SIZE46);
634 } else {
635 connPtr->proxypeer[0] = '\0';
636 }
637
638 return connPtr->peer;
639}
640
641
642/*
643 *----------------------------------------------------------------------
644 *
645 * Ns_ConnPeerPort --
646 *
647 * Get the port from which the peer is coming
648 *
649 * Results:
650 * The port number.
651 *
652 * Side effects:
653 * None
654 *
655 *----------------------------------------------------------------------
656 */
657
658unsigned short
659Ns_ConnPeerPort(const Ns_Conn *conn)
660{
661 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
662
663 return ((const Conn *)conn)->reqPtr->port;
664}
665
666
667/*
668 *----------------------------------------------------------------------
669 * Ns_SetConnLocationProc --
670 *
671 * Set pointer to custom routine that acts like
672 * Ns_ConnLocationAppend();
673 *
674 * Results:
675 * NS_OK or NS_ERROR.
676 *
677 * Side effects:
678 * Overrides an old-style Ns_LocationProc.
679 *
680 *----------------------------------------------------------------------
681 */
682
683Ns_ReturnCode
684Ns_SetConnLocationProc(Ns_ConnLocationProc *proc, Ns_TclCallback *cbPtr)
685{
686 Ns_ReturnCode status = NS_OK;
687 NsServer *servPtr = NsGetInitServer();
688
689 NS_NONNULL_ASSERT(proc != NULL)((void) (0));
690 NS_NONNULL_ASSERT(cbPtr != NULL)((void) (0));
691
692 if (servPtr == NULL((void*)0)) {
693 Ns_Log(Error, "Ns_SetConnLocationProc: no initializing server");
694 status = NS_ERROR;
695 } else {
696 servPtr->vhost.connLocationProc = proc;
697 servPtr->vhost.connLocationArg = cbPtr;
698 }
699
700 return status;
701}
702
703
704/*
705 *----------------------------------------------------------------------
706 * Ns_SetLocationProc --
707 *
708 * Set pointer to custom routine that acts like Ns_ConnLocation();
709 *
710 * Deprecated: Use Ns_SetConnLocationProc() which is virtual host
711 * aware.
712 *
713 * Results:
714 * None
715 *
716 * Side effects:
717 * None
718 *
719 *----------------------------------------------------------------------
720 */
721
722void
723Ns_SetLocationProc(const char *server, Ns_LocationProc *proc)
724{
725 NsServer *servPtr = NsGetServer(server);
726
727 NS_NONNULL_ASSERT(server != NULL)((void) (0));
728 NS_NONNULL_ASSERT(proc != NULL)((void) (0));
729
730 if (servPtr != NULL((void*)0)) {
731 servPtr->vhost.locationProc = proc;
732 }
733}
734
735
736/*
737 *----------------------------------------------------------------------
738 *
739 * Ns_ConnLocation --
740 *
741 * Get the location according to the driver for this connection.
742 * It is of the form SCHEME://HOSTNAME:PORT
743 *
744 * Deprecated: Use Ns_ConnLocationAppend() which is virtual host
745 * aware.
746 *
747 * Results:
748 * A string URL, not including path
749 *
750 * Side effects:
751 * None
752 *
753 *----------------------------------------------------------------------
754 */
755
756const char *
757Ns_ConnLocation(Ns_Conn *conn)
758{
759 const Conn *connPtr = (const Conn *) conn;
760 const NsServer *servPtr = connPtr->poolPtr->servPtr;
761 const char *location = NULL((void*)0);
762
763 if (servPtr->vhost.locationProc != NULL((void*)0)) {
764 location = (*servPtr->vhost.locationProc)(conn);
765 }
766 if (location == NULL((void*)0)) {
767 location = connPtr->location;
768 }
769
770 return location;
771}
772
773
774/*
775 *----------------------------------------------------------------------
776 *
777 * Ns_ConnLocationAppend --
778 *
779 * Append the location of this connection to dest. It is of the
780 * form SCHEME://HOSTNAME:PORT
781 *
782 * Results:
783 * dest->string.
784 *
785 * Side effects:
786 * None
787 *
788 *----------------------------------------------------------------------
789 */
790
791char *
792Ns_ConnLocationAppend(Ns_Conn *conn, Ns_DStringTcl_DString *dest)
793{
794 const Conn *connPtr;
795 const NsServer *servPtr;
796 const Ns_Set *headers;
797 const char *host;
798 char *location = NULL((void*)0);
799
800 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
801 NS_NONNULL_ASSERT(dest != NULL)((void) (0));
802
803 connPtr = ((Conn *)conn);
804 assert(connPtr->poolPtr != NULL)((void) (0));
805
806 servPtr = connPtr->poolPtr->servPtr;
807 assert(servPtr != NULL)((void) (0));
808
809 if (servPtr->vhost.connLocationProc != NULL((void*)0)) {
810
811 /*
812 * Prefer the new style Ns_ConnLocationProc.
813 */
814
815 location = (*servPtr->vhost.connLocationProc)(conn, dest, servPtr->vhost.connLocationArg);
816
817 } else if (servPtr->vhost.locationProc != NULL((void*)0)) {
818
819 /*
820 * Fall back to old style Ns_LocationProc.
821 */
822
823 location = (*servPtr->vhost.locationProc)(conn);
824 if (location != NULL((void*)0)) {
825 location = Ns_DStringAppend(dest, location)Tcl_DStringAppend((dest), (location), -1);
826 }
827
828 } else if (servPtr->vhost.enabled
829 && ((headers = Ns_ConnHeaders(conn)) != NULL((void*)0))
830 && ((host = Ns_SetIGet(headers, "Host")) != NULL((void*)0))
831 && (*host != '\0')) {
832 /*
833 * Construct a location string from the HTTP "host" header field
834 * without using port and default port.
835 */
836 if (Ns_StrIsValidHostHeaderContent(host)) {
837 location = Ns_HttpLocationString(dest, connPtr->drvPtr->protocol, host, 0u, 0u);
838 }
839 }
840
841 /*
842 * If everything above failed, try the location form the connPtr. This is
843 * actually determine from sockPtr->location which comes from
844 * mapPtr->location, which comes from the virtual hosts mapping table.
845 */
846 if ((location == NULL((void*)0)) && (connPtr->location != NULL((void*)0))) {
847 location = Ns_DStringAppend(dest, connPtr->location)Tcl_DStringAppend((dest), (connPtr->location), -1);
848 }
849
850 /*
851 * If everything above failed, try the static driver location or - as last
852 * resort - use the configured address.
853 */
854
855 if (location == NULL((void*)0)) {
856 unsigned short port;
857 const char *addr;
858
859 if (connPtr->sockPtr != NULL((void*)0)) {
860 port = Ns_SockGetPort((Ns_Sock*)connPtr->sockPtr);
861 addr = Ns_SockGetAddr((Ns_Sock*)connPtr->sockPtr);
862 } else {
863 port = connPtr->drvPtr->port;
864 addr = connPtr->drvPtr->address;
865 }
866 location = Ns_HttpLocationString(dest, connPtr->drvPtr->protocol,
867 addr, port, connPtr->drvPtr->defport);
868 }
869
870 return location;
871}
872
873/*
874 *----------------------------------------------------------------------
875 *
876 * ConnGetDriver --
877 *
878 * Return the Driver for a connection
879 *
880 * Results:
881 * configured driver
882 *
883 * Side effects:
884 * None
885 *
886 *----------------------------------------------------------------------
887 */
888static const Ns_Driver*
889ConnGetDriver(const Ns_Conn *conn)
890{
891 return (Ns_Driver *)((const Conn *)conn)->drvPtr;
892}
893
894
895
896/*
897 *----------------------------------------------------------------------
898 *
899 * Ns_ConnHost --
900 *
901 * Get the address of the current connection
902 *
903 * Results:
904 * A string address
905 *
906 * Side effects:
907 * None
908 *
909 *----------------------------------------------------------------------
910 */
911
912const char *
913Ns_ConnHost(const Ns_Conn *conn)
914{
915 const Ns_Driver *drvPtr;
916
917 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
918
919 drvPtr = ConnGetDriver(conn);
920 assert(drvPtr != NULL)((void) (0));
921
922 return drvPtr->address;
923}
924
925
926/*
927 *----------------------------------------------------------------------
928 *
929 * Ns_ConnPort --
930 *
931 * What server port is this connection on?
932 *
933 * Results:
934 * Integer port number
935 *
936 * Side effects:
937 * None
938 *
939 *----------------------------------------------------------------------
940 */
941
942unsigned short
943Ns_ConnPort(const Ns_Conn *conn)
944{
945 const Driver *drvPtr;
946
947 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
948
949 drvPtr = ((const Conn *)conn)->drvPtr;
950 assert(drvPtr != NULL)((void) (0));
951
952 return drvPtr->port;
953}
954
955
956/*
957 *----------------------------------------------------------------------
958 *
959 * Ns_ConnSock --
960 *
961 * Return the underlying socket for a connection.
962 *
963 * Results:
964 * socket descriptor
965 *
966 * Side effects:
967 * None
968 *
969 *----------------------------------------------------------------------
970 */
971
972NS_SOCKETint
973Ns_ConnSock(const Ns_Conn *conn)
974{
975 const Sock *sockPtr;
976
977 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
978
979 sockPtr = ((const Conn *)conn)->sockPtr;
980
981 return (sockPtr != NULL((void*)0)) ? sockPtr->sock : NS_INVALID_SOCKET(-1);
982}
983
984/*
985 *----------------------------------------------------------------------
986 *
987 * Ns_ConnSockPtr --
988 *
989 * Return the underlying socket for a connection.
990 *
991 * Results:
992 * Ns_sock struct
993 *
994 * Side effects:
995 * None
996 *
997 *----------------------------------------------------------------------
998 */
999
1000Ns_Sock *
1001Ns_ConnSockPtr(const Ns_Conn *conn)
1002{
1003 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1004
1005 return (Ns_Sock *)(((const Conn *)conn))->sockPtr;
1006}
1007
1008/*
1009 *----------------------------------------------------------------------
1010 *
1011 * Ns_ConnSockContent --
1012 *
1013 * Returns read buffer for incoming requests.
1014 *
1015 * Results:
1016 * NULL if no content have been read yet
1017 *
1018 * Side effects:
1019 * None
1020 *
1021 *----------------------------------------------------------------------
1022 */
1023
1024Ns_DStringTcl_DString *
1025Ns_ConnSockContent(const Ns_Conn *conn)
1026{
1027 Request *reqPtr;
1028 Ns_DStringTcl_DString *result;
1029
1030 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1031
1032 reqPtr = ((const Conn *)conn)->reqPtr;
1033 if (likely(reqPtr != NULL)(__builtin_expect((reqPtr != ((void*)0)), 1))) {
1034 result = &(reqPtr->buffer);
1035 } else {
1036 result = NULL((void*)0);
1037 }
1038 return result;
1039}
1040
1041
1042/*
1043 *----------------------------------------------------------------------
1044 *
1045 * Ns_ConnDriverName --
1046 *
1047 * Return the name of this driver
1048 *
1049 * Results:
1050 * A driver name
1051 *
1052 * Side effects:
1053 * None
1054 *
1055 *----------------------------------------------------------------------
1056 */
1057
1058const char *
1059Ns_ConnDriverName(const Ns_Conn *conn)
1060{
1061 const Ns_Driver *drvPtr;
1062
1063 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1064
1065 drvPtr = ConnGetDriver(conn);
1066 assert(drvPtr != NULL)((void) (0));
1067
1068 return drvPtr->moduleName;
1069}
1070
1071
1072/*
1073 *----------------------------------------------------------------------
1074 *
1075 * Ns_ConnStartTime --
1076 *
1077 * Return the connection start time, which is the time the
1078 * connection was queued from the driver thread, not the time the
1079 * underlying socket was opened to the server. Similarly
1080 * Ns_ConnAcceptTime() returns the time the connection was
1081 * accepted (this is maybe a kept open connection),
1082 * Ns_ConnQueueTime() returns the time a request was queued,
1083 * Ns_ConnDequeueTime() returns the time a request was taken out
1084 * of the queue, and Ns_ConnFilterTime() is the timestamp after
1085 * the filters are executed.
1086 *
1087 * Results:
1088 * Ns_Time pointer.
1089 *
1090 * Side effects:
1091 * None
1092 *
1093 *----------------------------------------------------------------------
1094 */
1095
1096Ns_Time *
1097Ns_ConnStartTime(Ns_Conn *conn)
1098{
1099 Conn *connPtr = (Conn *) conn;
1100
1101 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1102 return &connPtr->requestQueueTime;
1103}
1104
1105Ns_Time *
1106Ns_ConnAcceptTime(Ns_Conn *conn)
1107{
1108 Conn *connPtr = (Conn *) conn;
1109
1110 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1111 return &connPtr->acceptTime;
1112}
1113
1114Ns_Time *
1115Ns_ConnQueueTime(Ns_Conn *conn)
1116{
1117 Conn *connPtr = (Conn *) conn;
1118
1119 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1120 return &connPtr->requestQueueTime;
1121}
1122
1123Ns_Time *
1124Ns_ConnDequeueTime(Ns_Conn *conn)
1125{
1126 Conn *connPtr = (Conn *) conn;
1127
1128 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1129 return &connPtr->requestDequeueTime;
1130}
1131
1132Ns_Time *
1133Ns_ConnFilterTime(Ns_Conn *conn)
1134{
1135 Conn *connPtr = (Conn *) conn;
1136
1137 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1138 return &connPtr->filterDoneTime;
1139}
1140
1141
1142/*
1143 *----------------------------------------------------------------------
1144 *
1145 * Ns_ConnTimeSpans --
1146 *
1147 * Return for a given connection the time spans computed by
1148 * Ns_ConnTimeStats()
1149 *
1150 * Results:
1151 * Four time structures (argument 2 to 5)
1152 *
1153 * Side effects:
1154 * None.
1155 *
1156 *----------------------------------------------------------------------
1157 */
1158void
1159Ns_ConnTimeSpans(const Ns_Conn *conn,
1160 Ns_Time *acceptTimeSpanPtr, Ns_Time *queueTimeSpanPtr,
1161 Ns_Time *filterTimeSpanPtr, Ns_Time *runTimeSpanPtr) {
1162 const Conn *connPtr;
1163
1164 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1165 NS_NONNULL_ASSERT(acceptTimeSpanPtr != NULL)((void) (0));
1166 NS_NONNULL_ASSERT(queueTimeSpanPtr != NULL)((void) (0));
1167 NS_NONNULL_ASSERT(filterTimeSpanPtr != NULL)((void) (0));
1168 NS_NONNULL_ASSERT(runTimeSpanPtr != NULL)((void) (0));
1169
1170 connPtr = (const Conn *) conn;
1171 *acceptTimeSpanPtr = connPtr->acceptTimeSpan;
1172 *queueTimeSpanPtr = connPtr->queueTimeSpan;
1173 *filterTimeSpanPtr = connPtr->filterTimeSpan;
1174 *runTimeSpanPtr = connPtr->runTimeSpan;
1175}
1176
1177
1178/*
1179 *----------------------------------------------------------------------
1180 *
1181 * NsConnTimeStatsUpdate --
1182 *
1183 * Compute for a given connection various time spans such as
1184 * acceptTimeSpan, queueTimeSpan, filterTimeSpan and
1185 * runTimeSpan as follows
1186 *
1187 * acceptTimeSpan = queueTime - acceptTime
1188 * queueTimeSpan = dequeueTime - queueTime
1189 * filterTimeSpan = filterDoneTime - dequeueTime
1190 * runTimeSpan = runDoneTime - filterDoneTime
1191 *
1192 *
1193 * Results:
1194 * None.
1195 *
1196 * Side effects:
1197 * Update time span values in connPtr
1198 *
1199 *----------------------------------------------------------------------
1200 */
1201void
1202NsConnTimeStatsUpdate(Ns_Conn *conn) {
1203 Conn *connPtr;
1204
1205 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1206
1207 connPtr = (Conn *) conn;
1208
1209 Ns_GetTime(&connPtr->runDoneTime);
1210
1211 (void)Ns_DiffTime(&connPtr->requestQueueTime, &connPtr->acceptTime, &connPtr->acceptTimeSpan);
Duplicate code detected
1212 (void)Ns_DiffTime(&connPtr->requestDequeueTime, &connPtr->requestQueueTime, &connPtr->queueTimeSpan);
Similar code here
1213 (void)Ns_DiffTime(&connPtr->filterDoneTime, &connPtr->requestDequeueTime, &connPtr->filterTimeSpan);
1214 (void)Ns_DiffTime(&connPtr->runDoneTime, &connPtr->filterDoneTime, &connPtr->runTimeSpan);
1215
1216}
1217
1218
1219/*
1220 *----------------------------------------------------------------------
1221 *
1222 * NsConnTimeStatsFinalize --
1223 *
1224 * Record the time after running the connection main task and the end of
1225 * the processing of this task called traceTimeSpan. This value is
1226 * calculated as follows:
1227 *
1228 * traceTimeSpan = now - runDoneTime
1229 *
1230 * In addition, this function updates the statistics and should
1231 * be called only once per request.
1232 *
1233 * Results:
1234 * None.
1235 *
1236 * Side effects:
1237 * Update statistics.
1238 *
1239 *----------------------------------------------------------------------
1240 */
1241void
1242NsConnTimeStatsFinalize(const Ns_Conn *conn) {
1243 const Conn *connPtr;
1244 ConnPool *poolPtr;
1245 Ns_Time now, diffTimeSpan;
1246
1247 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1248
1249 connPtr = (const Conn *) conn;
1250 poolPtr = connPtr->poolPtr;
1251 assert(poolPtr != NULL)((void) (0));
1252
1253 Ns_GetTime(&now);
1254
1255 (void)Ns_DiffTime(&now, &connPtr->runDoneTime, &diffTimeSpan);
1256
1257 Ns_MutexLock(&poolPtr->threads.lock);
1258 Ns_IncrTime(&poolPtr->stats.acceptTime, connPtr->acceptTimeSpan.sec, connPtr->acceptTimeSpan.usec);
1259 Ns_IncrTime(&poolPtr->stats.queueTime, connPtr->queueTimeSpan.sec, connPtr->queueTimeSpan.usec);
1260 Ns_IncrTime(&poolPtr->stats.filterTime, connPtr->filterTimeSpan.sec, connPtr->filterTimeSpan.usec);
1261 Ns_IncrTime(&poolPtr->stats.runTime, connPtr->runTimeSpan.sec, connPtr->runTimeSpan.usec);
1262 Ns_IncrTime(&poolPtr->stats.traceTime, diffTimeSpan.sec, diffTimeSpan.usec);
1263 Ns_MutexUnlock(&poolPtr->threads.lock);
1264}
1265
1266
1267
1268/*
1269 *----------------------------------------------------------------------
1270 *
1271 * Ns_ConnTimeout --
1272 *
1273 * Absolute time value beyond which conn should not wait on
1274 * resources, such as condition variables.
1275 *
1276 * Results:
1277 * Ns_Time pointer.
1278 *
1279 * Side effects:
1280 * None.
1281 *
1282 *----------------------------------------------------------------------
1283 */
1284
1285Ns_Time *
1286Ns_ConnTimeout(Ns_Conn *conn)
1287{
1288 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1289
1290 return &((Conn *)conn)->timeout;
1291}
1292
1293
1294/*
1295 *----------------------------------------------------------------------
1296 *
1297 * Ns_ConnId --
1298 *
1299 * Return the connection id.
1300 *
1301 * Results:
1302 * The connection id.
1303 *
1304 * Side effects:
1305 * None
1306 *
1307 *----------------------------------------------------------------------
1308 */
1309
1310uintptr_t
1311Ns_ConnId(const Ns_Conn *conn)
1312{
1313 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1314
1315 return ((const Conn *)conn)->id;
1316}
1317
1318const char *
1319NsConnIdStr(const Ns_Conn *conn)
1320{
1321 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1322
1323 return ((const Conn *)conn)->idstr;
1324}
1325
1326
1327
1328
1329/*
1330 *----------------------------------------------------------------------
1331 *
1332 * Ns_ConnModifiedSince --
1333 *
1334 * Has the data the url points to changed since a given time?
1335 *
1336 * Results:
1337 * NS_TRUE if data modified, NS_FALSE otherwise.
1338 *
1339 * Side effects:
1340 * None
1341 *
1342 * NOTE: This doesn't do a strict time check. If the server flags aren't
1343 * set to check modification, or if there wasn't an 'If-Modified-Since'
1344 * header in the request, then this'll always return true.
1345 *
1346 *----------------------------------------------------------------------
1347 */
1348
1349bool_Bool
1350Ns_ConnModifiedSince(const Ns_Conn *conn, time_t since)
1351{
1352 const ConnPool *poolPtr;
1353 bool_Bool result = NS_TRUE1;
1354
1355 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1356
1357 poolPtr = ((const Conn *)conn)->poolPtr;
1358 assert(poolPtr != NULL)((void) (0));
1359 assert(poolPtr->servPtr != NULL)((void) (0));
1360
1361 if (poolPtr->servPtr->opts.modsince) {
1362 const char *hdr = Ns_SetIGet(conn->headers, "If-Modified-Since");
1363
1364 if ((hdr != NULL((void*)0)) && (Ns_ParseHttpTime(hdr) >= since)) {
1365 result = NS_FALSE0;
1366 }
1367 }
1368 return result;
1369}
1370
1371
1372/*
1373 *----------------------------------------------------------------------
1374 *
1375 * Ns_ConnUnmodifiedSince --
1376 *
1377 * Has the data the url points to changed since a given time?
1378 *
1379 * Results:
1380 * NS_TRUE if data unmodified or header not present, NS_FALSE otherwise.
1381 *
1382 * Side effects:
1383 * None
1384 *
1385 *----------------------------------------------------------------------
1386 */
1387
1388bool_Bool
1389Ns_ConnUnmodifiedSince(const Ns_Conn *conn, time_t since)
1390{
1391 const char *hdr;
1392 bool_Bool result = NS_TRUE1;
1393
1394 hdr = Ns_SetIGet(conn->headers, "If-Unmodified-Since");
1395 if ((hdr != NULL((void*)0)) && (Ns_ParseHttpTime(hdr) < since)) {
1396 result = NS_FALSE0;
1397 }
1398 return result;
1399}
1400
1401
1402/*
1403 *----------------------------------------------------------------------
1404 *
1405 * Ns_ConnGetEncoding, Ns_ConnSetEncoding --
1406 *
1407 * Get (set) the Tcl_Encoding for the connection which is used
1408 * to convert from UTF to specified output character set.
1409 *
1410 * Results:
1411 * Pointer to Tcl_Encoding (get) or NULL (set).
1412 *
1413 * Side effects:
1414 * See Ns_ConnGetQuery().
1415 *
1416 *----------------------------------------------------------------------
1417 */
1418
1419Tcl_Encoding
1420Ns_ConnGetEncoding(const Ns_Conn *conn)
1421{
1422 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1423
1424 return ((const Conn *) conn)->outputEncoding;
1425}
1426
1427void
1428Ns_ConnSetEncoding(Ns_Conn *conn, Tcl_Encoding encoding)
1429{
1430 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1431
1432 ((Conn *) conn)->outputEncoding = encoding;
1433}
1434
1435
1436/*
1437 *----------------------------------------------------------------------
1438 *
1439 * Ns_ConnGetUrlEncoding, Ns_ConnSetUrlEncoding --
1440 *
1441 * Get (set) the Tcl_Encoding for the connection which is used
1442 * to convert input forms to proper UTF.
1443 *
1444 * Results:
1445 * Pointer to Tcl_Encoding (get) or NULL (set).
1446 *
1447 * Side effects:
1448 * See Ns_ConnGetQuery().
1449 *
1450 *----------------------------------------------------------------------
1451 */
1452
1453Tcl_Encoding
1454Ns_ConnGetUrlEncoding(const Ns_Conn *conn)
1455{
1456 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1457
1458 return ((const Conn *) conn)->urlEncoding;
1459}
1460
1461void
1462Ns_ConnSetUrlEncoding(Ns_Conn *conn, Tcl_Encoding encoding)
1463{
1464 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1465
1466 ((Conn *) conn)->urlEncoding = encoding;
1467}
1468
1469
1470/*
1471 *----------------------------------------------------------------------
1472 *
1473 * Ns_ConnGetCompression, Ns_ConnSetCompression
1474 *
1475 * Get configured compression level (*Get*) or enable/disable compression
1476 * with the specified level (*Set*). Output will only be compressed if
1477 * client advertises support.
1478 *
1479 * Level 1 is 'on' i.e. default compression from config.
1480 *
1481 * Results:
1482 * Compression level, 0-9.
1483 *
1484 * Side effects:
1485 * None.
1486 *
1487 *----------------------------------------------------------------------
1488 */
1489
1490int
1491Ns_ConnGetCompression(const Ns_Conn *conn)
1492{
1493 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1494
1495 return ((const Conn *) conn)->requestCompress;
1496}
1497
1498void
1499Ns_ConnSetCompression(Ns_Conn *conn, int level)
1500{
1501 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
1502
1503#ifdef HAVE_ZLIB_H1
1504 ((Conn *) conn)->requestCompress = MIN(MAX(level, 0), 9)((((((level)>(0))?(level):(0)))<(9))?((((level)>(0))
?(level):(0))):(9))
;
1505#else
1506 ((Conn *) conn)->requestCompress = 0;
1507#endif
1508}
1509
1510
1511/*
1512 *----------------------------------------------------------------------
1513 *
1514 * NsTclConnObjCmd --
1515 *
1516 * Implements "ns_conn".
1517 *
1518 * Results:
1519 * Standard Tcl result.
1520 *
1521 * Side effects:
1522 * See docs.
1523 *
1524 *----------------------------------------------------------------------
1525 */
1526
1527int
1528NsTclConnObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
1529{
1530 NsInterp *itPtr = clientData;
1531 Conn *connPtr;
1532 Ns_Conn *conn;
1533 const Ns_Request *request = NULL((void*)0);
1534 Tcl_Encoding encoding;
1535 Tcl_Channel chan;
1536 const Tcl_HashEntry *hPtr;
1537 Tcl_HashSearch search;
1538 int setNameLength, opt = 0, result = TCL_OK0;
1539 const char *setName;
1540
1541 static const char *const opts[] = {
1542 "acceptedcompression", "auth", "authpassword", "authuser",
1543 "channel", "clientdata", "close", "compress", "content",
1544 "contentfile", "contentlength", "contentsentlength", "copy",
1545 "currentaddr", "currentport",
1546 "driver",
1547 "encoding",
1548 "fileheaders", "filelength", "fileoffset", "files", "flags", "form",
1549 "headerlength", "headers", "host",
1550 "id", "isconnected",
1551 "keepalive",
1552 "location",
1553 "method",
1554 "outputheaders",
1555 "partialtimes", "peeraddr", "peerport", "pool", "port", "protocol",
1556 "query",
1557 "ratelimit", "request",
1558 "server", "sock", "start", "status",
1559 "timeout",
1560 "url", "urlc", "urlencoding", "urlv",
1561 "version",
1562 "zipaccepted",
1563 NULL((void*)0)
1564 };
1565 static const unsigned int required_flags[] = {
1566 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_CONFIGURED0x1000000u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1567 NS_CONN_REQUIRE_OPEN0x0002u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_OPEN0x0002u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1568 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_OPEN0x0002u, NS_CONN_REQUIRE_OPEN0x0002u,
1569 NS_CONN_REQUIRE_CONNECTED0x0001u, NS_CONN_REQUIRE_CONNECTED0x0001u,
1570 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1571 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1572 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1573 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1574 NS_CONN_REQUIRE_CONFIGURED0x0004u, 0u,
1575 NS_CONN_REQUIRE_CONNECTED0x0001u,
1576 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1577 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1578 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1579 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONNECTED0x0001u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1580 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1581 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1582 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONNECTED0x0001u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1583 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1584 NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u, NS_CONN_REQUIRE_CONFIGURED0x0004u,
1585 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1586 NS_CONN_REQUIRE_CONFIGURED0x0004u,
1587 0u
1588 };
1589 enum ISubCmdIdx {
1590 CAacceptedcompressionIdx, CAuthIdx, CAuthPasswordIdx, CAuthUserIdx,
1591 CChannelIdx, CClientdataIdx, CCloseIdx, CCompressIdx, CContentIdx,
1592 CContentFileIdx, CContentLengthIdx, CContentSentLenIdx, CCopyIdx,
1593 CCurrentAddrIdx, CCurrentPortIdx,
1594 CDriverIdx,
1595 CEncodingIdx,
1596 CFileHdrIdx, CFileLenIdx, CFileOffIdx, CFilesIdx, CFlagsIdx, CFormIdx,
1597 CHeaderLengthIdx, CHeadersIdx, CHostIdx,
1598 CIdIdx, CIsConnectedIdx,
1599 CKeepAliveIdx,
1600 CLocationIdx,
1601 CMethodIdx,
1602 COutputHeadersIdx,
1603 CPartialTimesIdx, CPeerAddrIdx, CPeerPortIdx, CPoolIdx, CPortIdx, CProtocolIdx,
1604 CQueryIdx,
1605 CRatelimitIdx, CRequestIdx,
1606 CServerIdx, CSockIdx, CStartIdx, CStatusIdx,
1607 CTimeoutIdx,
1608 CUrlIdx, CUrlcIdx, CUrlEncodingIdx, CUrlvIdx,
1609 CVersionIdx,
1610 CZipacceptedIdx
1611 };
1612
1613 assert(itPtr != NULL)((void) (0));
1614 conn = itPtr->conn;
1615 connPtr = (Conn *)conn;
1616
1617 if (unlikely(objc < 2)(__builtin_expect((objc < 2), 0))) {
1618 Tcl_WrongNumArgs(interp, 1, objv, "option");
1619 opt = (int)CIsConnectedIdx; /* silence static checker */
1620 result = TCL_ERROR1;
1621
1622 } else if (unlikely(Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0,(__builtin_expect((Tcl_GetIndexFromObjStruct(interp, objv[1],
opts, sizeof(char *), "option", 0, &opt) != 0), 0))
1623 &opt) != TCL_OK)(__builtin_expect((Tcl_GetIndexFromObjStruct(interp, objv[1],
opts, sizeof(char *), "option", 0, &opt) != 0), 0))
) {
1624 result = TCL_ERROR1;
1625 } else if (required_flags[opt] != 0u) {
1626 /*
1627 * We have to check the connection requirements.
1628 */
1629 if (NsConnRequire(interp, required_flags[opt], NULL((void*)0)) != NS_OK) {
1630 result = TCL_ERROR1;
1631 } else {
1632 /*
1633 * We know that connPtr can't be NULL.
1634 */
1635 assert(conn != NULL)((void) (0));
1636 request = &connPtr->request;
1637 }
1638 } else {
1639 request = &connPtr->request;
1640 }
1641
1642 if (result == TCL_ERROR1) {
1643 return result;
1644 }
1645
1646 /*
1647 * Each time, when NsConnRequire was called and succeeded, the request
1648 * must be not NULL.
1649 */
1650 if (required_flags[opt] != 0u) {
1651 assert(request != NULL)((void) (0));
1652 }
1653
1654 switch (opt) {
1655 case CIsConnectedIdx:
1656 /*
1657 * We report true, when we have a connection and the connection is not
1658 * closed.
1659 */
1660 Tcl_SetObjResult(interp, Tcl_NewBooleanObj((connPtr != NULL)Tcl_NewIntObj(((connPtr != ((void*)0)) ? ((connPtr->flags &
0x001u) == 0u) : 0)!=0)
1661 ? ((connPtr->flags & NS_CONN_CLOSED) == 0u)Tcl_NewIntObj(((connPtr != ((void*)0)) ? ((connPtr->flags &
0x001u) == 0u) : 0)!=0)
1662 : NS_FALSE)Tcl_NewIntObj(((connPtr != ((void*)0)) ? ((connPtr->flags &
0x001u) == 0u) : 0)!=0)
);
1663 break;
1664
1665 case CKeepAliveIdx:
1666 {
1667 Ns_ObjvValueRange keepRange = {0, 1};
1668 int oc = 1;
1669 Ns_ObjvSpec spec = {"?size", Ns_ObjvInt, &connPtr->keep, &keepRange};
1670
1671 if (objc > 2 && Ns_ObjvInt(&spec, interp, &oc, &objv[2]) != TCL_OK0) {
1672 result = TCL_ERROR1;
1673 }
1674 if (result == TCL_OK0) {
1675 Tcl_SetObjResult(interp, Tcl_NewIntObj(connPtr->keep));
1676 }
1677 }
1678 break;
1679
1680 case CClientdataIdx:
1681 if (objc > 2) {
1682 const char *value = Tcl_GetString(objv[2]);
1683 if (connPtr->clientData != NULL((void*)0)) {
1684 ns_free(connPtr->clientData);
1685 }
1686 connPtr->clientData = ns_strdup(value);
1687 }
1688 Tcl_SetObjResult(interp, Tcl_NewStringObj(connPtr->clientData, -1));
1689 break;
1690
1691 case CCompressIdx:
1692 if (objc > 2) {
1693 Ns_ObjvValueRange compressRange = {0, 9};
1694 int oc = 1, level = 0;
1695 Ns_ObjvSpec spec = {"?level", Ns_ObjvInt, &level, &compressRange};
1696
1697 if (Ns_ObjvInt(&spec, interp, &oc, &objv[2]) != TCL_OK0) {
1698 result = TCL_ERROR1;
1699
1700 } else {
1701 Ns_ConnSetCompression(conn, level);
1702 }
1703 }
1704 if (result == TCL_OK0) {
1705 Tcl_SetObjResult(interp,
1706 Tcl_NewIntObj(Ns_ConnGetCompression(conn)));
1707 }
1708 break;
1709
1710 case CUrlvIdx:
1711 if (objc == 2) {
1712 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->urlv, request->urlv_len));
1713 } else {
1714 Ns_ObjvValueRange idxRange = {0, request->urlc - 1};
1715 int oc = 1, idx = 0;
1716 Ns_ObjvSpec spec = {"?idx", Ns_ObjvInt, &idx, &idxRange};
1717
1718 if (Ns_ObjvInt(&spec, interp, &oc, &objv[2]) != TCL_OK0) {
1719 result = TCL_ERROR1;
1720 } else {
1721 const char **elements;
1722 int length;
1723
1724 (void)Tcl_SplitList(NULL((void*)0), request->urlv, &length, &elements);
1725 Tcl_SetObjResult(interp, Tcl_NewStringObj(elements[idx], -1));
1726 Tcl_Free((char *) elements);
1727 }
1728 }
1729 break;
1730
1731 case CCurrentAddrIdx:
1732 {
1733 const char *addr = Ns_ConnCurrentAddr(conn);
1734
1735 Tcl_SetObjResult(interp, Tcl_NewStringObj((addr != NULL((void*)0)) ? addr : NS_EMPTY_STRING, -1));
1736 }
1737 break;
1738
1739 case CCurrentPortIdx:
1740 {
1741 unsigned short port = Ns_ConnCurrentPort(conn);
1742
1743 Tcl_SetObjResult(interp, Tcl_NewIntObj((int)port));
1744 }
1745 break;
1746
1747
1748 case CAuthIdx:
1749 if ((itPtr->nsconn.flags & CONN_TCLAUTH0x08u) != 0u) {
1750 Tcl_SetResult(interp, itPtr->nsconn.auth, TCL_STATIC((Tcl_FreeProc *) 0));
1751 } else {
1752 if (connPtr->auth == NULL((void*)0)) {
1753 connPtr->auth = Ns_SetCreate(NS_SET_NAME_AUTH"auth");
1754 }
1755 if (unlikely(Ns_TclEnterSet(interp, connPtr->auth, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, connPtr->auth, NS_TCL_SET_STATIC
) != 0), 0))
) {
1756 result = TCL_ERROR1;
1757 } else {
1758 setName = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &setNameLength);
1759 setNameLength++;
1760 memcpy(itPtr->nsconn.auth, setName, MIN((size_t)setNameLength, NS_SET_SIZE)((((size_t)setNameLength)<(((unsigned)24 + 2u)))?((size_t)
setNameLength):(((unsigned)24 + 2u)))
);
1761 itPtr->nsconn.flags |= CONN_TCLAUTH0x08u;
1762 }
1763 }
1764 break;
1765
1766 case CAuthUserIdx:
1767 if (connPtr->auth != NULL((void*)0)) {
1768 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnAuthUser(conn), -1));
1769 }
1770 break;
1771
1772 case CAuthPasswordIdx:
1773 if (connPtr->auth != NULL((void*)0)) {
1774 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnAuthPasswd(conn), -1));
1775 }
1776 break;
1777
1778 case CContentIdx:
1779 {
1780 int binary = (int)NS_FALSE0, offset = 0, length = -1, requiredLength;
1781 Tcl_DString encDs;
1782 Ns_ObjvSpec lopts[] = {
1783 {"-binary", Ns_ObjvBool, &binary, INT2PTR(NS_TRUE)((void *)(intptr_t)(1))},
1784 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1785 };
1786 Ns_ObjvSpec args[] = {
1787 {"?offset", Ns_ObjvInt, &offset, &posintRange0},
1788 {"?length", Ns_ObjvInt, &length, &posintRange1},
1789 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1790 };
1791
1792 if (Ns_ParseObjv(lopts, args, interp, 2, objc, objv) != NS_OK) {
1793 result = TCL_ERROR1;
1794
1795 } else if ((connPtr->flags & NS_CONN_CLOSED0x001u) != 0u) {
1796 /*
1797 * In cases, the content is allocated via mmap, the content
1798 * is unmapped when the socket is closed. Accessing the
1799 * content will crash the server. Although we might not have
1800 * the same problem when the content is allocated
1801 * differently, we use here the restrictive strategy to
1802 * provide consistent behavior independent of the allocation
1803 * strategy.
1804 */
1805 Ns_TclPrintfResult(interp, "connection already closed, can't get content");
1806 result = TCL_ERROR1;
1807 }
1808
1809 requiredLength = length;
1810 if ((result == TCL_OK0)
1811 && (offset > 0)
1812 && ((size_t)offset > connPtr->reqPtr->length)
1813 ) {
1814 Ns_TclPrintfResult(interp, "offset exceeds available content length");
1815 result = TCL_ERROR1;
1816 }
1817
1818 if ((result == TCL_OK0) && (length == -1)) {
1819 length = (int)connPtr->reqPtr->length - offset;
1820
1821 } else if ((result == TCL_OK0)
1822 && (length > -1)
1823 && ((size_t)length + (size_t)offset > connPtr->reqPtr->length)
1824 ) {
1825 Ns_TclPrintfResult(interp, "offset + length exceeds available content length");
1826 result = TCL_ERROR1;
1827 }
1828
1829 if (result == TCL_OK0) {
1830 size_t contentLength;
1831 const char *content;
1832
1833 if (connPtr->reqPtr->length == 0u) {
1834 content = NULL((void*)0);
1835 contentLength = 0u;
1836 Tcl_ResetResult(interp);
1837 } else if (!binary) {
1838 content = Tcl_ExternalToUtfDString(connPtr->outputEncoding,
1839 connPtr->reqPtr->content,
1840 (int)connPtr->reqPtr->length,
1841 &encDs);
1842 contentLength = (size_t)Tcl_DStringLength(&encDs)((&encDs)->length);
1843 if (requiredLength == -1) {
1844 length = Tcl_DStringLength(&encDs)((&encDs)->length) - offset;
1845 }
1846 } else {
1847 content = connPtr->reqPtr->content;
1848 contentLength = connPtr->reqPtr->length;
1849 }
1850
1851 if (contentLength > 0u) {
1852 if (requiredLength == -1 && offset == 0) {
1853 /*
1854 * return full content
1855 */
1856 if (!binary) {
1857 Tcl_DStringResult(interp, &encDs);
1858 } else {
1859 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((uint8_t*)connPtr->reqPtr->content,
1860 (int)connPtr->reqPtr->length));
1861 }
1862 } else {
1863 /*
1864 * return partial content
1865 */
1866 if (!binary) {
1867 Tcl_Obj *contentObj = Tcl_NewStringObj(content, (int)contentLength);
1868
1869 Tcl_SetObjResult(interp, Tcl_GetRange(contentObj, offset, offset+length-1));
1870 Tcl_DStringFree(&encDs);
1871 Tcl_DecrRefCount(contentObj)do { Tcl_Obj *_objPtr = (contentObj); if (_objPtr->refCount
-- <= 1) { TclFreeObj(_objPtr); } } while(0)
;
1872 } else {
1873 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((const uint8_t*)content + offset,
1874 (int)length));
1875 }
1876 }
1877 }
1878 }
1879 break;
1880 }
1881
1882 case CContentLengthIdx:
1883 Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)conn->contentLength));
1884 break;
1885
1886 case CContentFileIdx:
1887 {
1888 const char *file = Ns_ConnContentFile(conn);
1889 if (file != NULL((void*)0)) {
1890 Tcl_SetObjResult(interp, Tcl_NewStringObj(file, -1));
1891 }
1892 }
1893 break;
1894
1895 case CEncodingIdx:
1896 if (objc > 2) {
1897 encoding = Ns_GetCharsetEncoding(Tcl_GetString(objv[2]));
1898 if (encoding == NULL((void*)0)) {
1899 Ns_TclPrintfResult(interp, "no such encoding: %s", Tcl_GetString(objv[2]));
1900 result = TCL_ERROR1;
1901 } else {
1902 connPtr->outputEncoding = encoding;
1903 }
1904 }
1905 if ((result == TCL_OK0) && (connPtr->outputEncoding != NULL((void*)0))) {
1906 const char *charset = Ns_GetEncodingCharset(connPtr->outputEncoding);
1907 Tcl_SetObjResult(interp, Tcl_NewStringObj(charset, -1));
1908 }
1909 break;
1910
1911 case CUrlEncodingIdx:
1912 if (objc > 2) {
1913 encoding = Ns_GetCharsetEncoding(Tcl_GetString(objv[2]));
1914 if (encoding == NULL((void*)0)) {
1915 Ns_TclPrintfResult(interp, "no such encoding: %s", Tcl_GetString(objv[2]));
1916 result = TCL_ERROR1;
1917 }
1918 /*
1919 * Check to see if form data has already been parsed.
1920 * If so, and the urlEncoding is changing, then clear
1921 * the previous form data.
1922 */
1923 if ((connPtr->urlEncoding != encoding)
1924 && (itPtr->nsconn.flags & CONN_TCLFORM0x01u) != 0u) {
1925
1926 Ns_ConnClearQuery(conn);
1927 itPtr->nsconn.flags ^= CONN_TCLFORM0x01u;
1928 }
1929 connPtr->urlEncoding = encoding;
1930 }
1931 if ((result == TCL_OK0) && (connPtr->urlEncoding != NULL((void*)0))) {
1932 const char *charset = Ns_GetEncodingCharset(connPtr->urlEncoding);
1933 Tcl_SetObjResult(interp, Tcl_NewStringObj(charset, -1));
1934 }
1935 break;
1936
1937 case CPeerAddrIdx: {
1938 int source = INTCHAR('c')((int)((unsigned char)(('c'))));
1939 static Ns_ObjvTable sourceTable[] = {
1940 {"configured", UCHAR('c')((unsigned char)('c'))},
1941 {"direct", UCHAR('d')((unsigned char)('d'))},
1942 {"forwarded", UCHAR('f')((unsigned char)('f'))},
1943 {NULL((void*)0), 0u}
1944 };
1945 Ns_ObjvSpec lopts[] = {
1946 {"-source", Ns_ObjvIndex, &source, sourceTable},
1947 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
1948 };
1949 if (Ns_ParseObjv(lopts, NULL((void*)0), interp, 2, objc, objv) != NS_OK) {
1950 result = TCL_ERROR1;
1951 } else if (source == INTCHAR('c')((int)((unsigned char)(('c'))))) {
1952 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnConfiguredPeerAddr(conn), -1));
1953 } else if (source == INTCHAR('d')((int)((unsigned char)(('d'))))) {
1954 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnPeerAddr(conn), -1));
1955 } else {
1956 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnForwardedPeerAddr(conn), -1));
1957 }
1958 break;
1959 }
1960
1961 case CPeerPortIdx:
1962 Tcl_SetObjResult(interp, Tcl_NewIntObj((int)Ns_ConnPeerPort(conn)));
1963 break;
1964
1965 case CHeaderLengthIdx:
1966 Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)connPtr->reqPtr->coff));
1967 break;
1968
1969 case CHeadersIdx:
1970 if (likely((itPtr->nsconn.flags & CONN_TCLHDRS) != 0u)(__builtin_expect(((itPtr->nsconn.flags & 0x02u) != 0u
), 1))
) {
1971 Tcl_SetResult(interp, itPtr->nsconn.hdrs, TCL_STATIC((Tcl_FreeProc *) 0));
1972 } else {
1973 if (unlikely(Ns_TclEnterSet(interp, connPtr->headers, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, connPtr->headers
, NS_TCL_SET_STATIC) != 0), 0))
) {
1974 result = TCL_ERROR1;
1975 } else {
1976 setName = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &setNameLength);
1977 setNameLength++;
1978 memcpy(itPtr->nsconn.hdrs, setName, MIN((size_t)setNameLength, NS_SET_SIZE)((((size_t)setNameLength)<(((unsigned)24 + 2u)))?((size_t)
setNameLength):(((unsigned)24 + 2u)))
);
1979 itPtr->nsconn.flags |= CONN_TCLHDRS0x02u;
1980 }
1981 }
1982 break;
1983
1984 case COutputHeadersIdx:
1985 if (likely((itPtr->nsconn.flags & CONN_TCLOUTHDRS) != 0u)(__builtin_expect(((itPtr->nsconn.flags & 0x04u) != 0u
), 1))
) {
1986 Tcl_SetResult(interp, itPtr->nsconn.outhdrs, TCL_STATIC((Tcl_FreeProc *) 0));
1987 } else {
1988 if (unlikely(Ns_TclEnterSet(interp, connPtr->outputheaders, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, connPtr->outputheaders
, NS_TCL_SET_STATIC) != 0), 0))
) {
1989 result = TCL_ERROR1;
1990 } else {
1991 setName = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &setNameLength);
1992 setNameLength++;
1993 memcpy(itPtr->nsconn.outhdrs, setName, MIN((size_t)setNameLength, NS_SET_SIZE)((((size_t)setNameLength)<(((unsigned)24 + 2u)))?((size_t)
setNameLength):(((unsigned)24 + 2u)))
);
1994 itPtr->nsconn.flags |= CONN_TCLOUTHDRS0x04u;
1995 }
1996 }
1997 break;
1998
1999 case CFormIdx:
2000 if ((itPtr->nsconn.flags & CONN_TCLFORM0x01u) != 0u) {
2001 Tcl_SetResult(interp, itPtr->nsconn.form, TCL_STATIC((Tcl_FreeProc *) 0));
2002 } else {
2003 Tcl_Obj *fallbackCharsetObj = NULL((void*)0);
2004 Ns_ObjvSpec lopts[] = {
2005 {"-fallbackcharset", Ns_ObjvObj, &fallbackCharsetObj, NULL((void*)0)},
2006 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
2007 };
2008 if (Ns_ParseObjv(lopts, NULL((void*)0), interp, 2, objc, objv) != NS_OK) {
2009 result = TCL_ERROR1;
2010 } else {
2011 Ns_ReturnCode rc = NS_OK;
2012 Ns_Set *form = Ns_ConnGetQuery(interp, conn, fallbackCharsetObj, &rc);
2013
2014 if (rc == NS_ERROR) {
2015 /*
2016 * Ns_ConnGetQuery() provides error message when rc != NS_OK;
2017 */
2018 result = TCL_ERROR1;
2019
2020 } else if (form == NULL((void*)0)) {
2021 itPtr->nsconn.form[0] = '\0';
2022 itPtr->nsconn.flags |= CONN_TCLFORM0x01u;
2023 } else {
2024 if (unlikely(Ns_TclEnterSet(interp, form, NS_TCL_SET_STATIC) != TCL_OK)(__builtin_expect((Ns_TclEnterSet(interp, form, NS_TCL_SET_STATIC
) != 0), 0))
) {
2025 result = TCL_ERROR1;
2026 } else {
2027 setName = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &setNameLength);
2028 setNameLength++;
2029 memcpy(itPtr->nsconn.form, setName, MIN((size_t)setNameLength, NS_SET_SIZE)((((size_t)setNameLength)<(((unsigned)24 + 2u)))?((size_t)
setNameLength):(((unsigned)24 + 2u)))
);
2030 itPtr->nsconn.flags |= CONN_TCLFORM0x01u;
2031 }
2032 }
2033 }
2034 }
2035 break;
2036
2037 case CFilesIdx:
2038 if (objc != 2) {
2039 Tcl_WrongNumArgs(interp, 2, objv, NULL((void*)0));
2040 result = TCL_ERROR1;
2041 } else {
2042 Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0));
2043
2044 for (hPtr = Tcl_FirstHashEntry(&connPtr->files, &search);
2045 hPtr != NULL((void*)0);
2046 hPtr = Tcl_NextHashEntry(&search)
2047 ) {
2048 const char *key = Tcl_GetHashKey(&connPtr->files, hPtr)((void *) (((&connPtr->files)->keyType == (1) || (&
connPtr->files)->keyType == (-1)) ? (hPtr)->key.oneWordValue
: (hPtr)->key.string))
;
2049 Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(key, -1));
2050 }
2051 Tcl_SetObjResult(interp, listObj);
2052 }
2053 break;
2054
2055 case CFileOffIdx: NS_FALL_THROUGH((void)0); /* fall through */
2056 case CFileLenIdx: NS_FALL_THROUGH((void)0); /* fall through */
2057 case CFileHdrIdx:
2058 if (objc != 3) {
2059 Tcl_WrongNumArgs(interp, 2, objv, NULL((void*)0));
2060 result = TCL_ERROR1;
2061 } else {
2062 hPtr = Tcl_FindHashEntry(&connPtr->files, Tcl_GetString(objv[2]))(*((&connPtr->files)->findProc))(&connPtr->files
, (const char *)(Tcl_GetString(objv[2])))
;
2063 if (hPtr == NULL((void*)0)) {
2064 Ns_TclPrintfResult(interp, "no such file: %s", Tcl_GetString(objv[2]));
2065 result = TCL_ERROR1;
2066 } else {
2067 const FormFile *filePtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData);
2068
2069 if (opt == (int)CFileOffIdx) {
2070 Tcl_SetObjResult(interp, (filePtr->offObj != NULL((void*)0)) ? filePtr->offObj : Tcl_NewObj());
2071 } else if (opt == (int)CFileLenIdx) {
2072 Tcl_SetObjResult(interp, (filePtr->sizeObj != NULL((void*)0)) ? filePtr->sizeObj : Tcl_NewObj());
2073 } else {
2074 Tcl_SetObjResult(interp, (filePtr->hdrObj != NULL((void*)0)) ? filePtr->hdrObj : Tcl_NewObj() );
2075 }
2076 }
2077 }
2078 break;
2079
2080 case CCopyIdx:
2081 if (objc != 5) {
2082 Tcl_WrongNumArgs(interp, 2, objv, "off len chan");
2083 result = TCL_ERROR1;
2084
2085 } else {
2086 int oc = 3, offset;
2087 Ns_ObjvValueRange offsetRange = {0, (Tcl_WideInt)connPtr->reqPtr->length};
2088 Ns_ObjvSpec specOffset = {"offset", Ns_ObjvInt, &offset, &offsetRange};
2089
2090 if (Ns_ObjvInt(&specOffset, interp, &oc, &objv[2]) != TCL_OK0) {
2091 result = TCL_ERROR1;
2092
2093 } else {
2094 int length;
2095 Ns_ObjvValueRange lengthRange = {0, ((Tcl_WideInt)connPtr->reqPtr->length - offset)};
2096 Ns_ObjvSpec specLength = {"length", Ns_ObjvInt, &length, &lengthRange};
2097
2098 if (Ns_ObjvInt(&specLength, interp, &oc, &objv[3]) != TCL_OK0) {
2099 result = TCL_ERROR1;
2100
2101 } else if (GetChan(interp, Tcl_GetString(objv[4]), &chan) != TCL_OK0) {
2102 result = TCL_ERROR1;
2103
2104 } else {
2105 char *content = connPtr->reqPtr->content + offset;
2106#ifdef NS_SKIPBOM
2107 Ns_Log(Notice, "NS_CONN COPY offset %d length %d chan '%s'\n",
2108 offset, length, Tcl_GetString(objv[4]));
2109 /*
2110 * The passed-in channel is binary. If this is the first
2111 * write operation, and file file starts with a BOM, then
2112 * strip it.
2113 */
2114 if (Tcl_Tell(chan) == 0 &&
2115 UCHAR(content[0])((unsigned char)(content[0])) == 0xEF &&
2116 UCHAR(content[1])((unsigned char)(content[1])) == 0xBB &&
2117 UCHAR(content[2])((unsigned char)(content[2])) == 0xBF) {
2118 Ns_Log(Notice, "NS_CONN COPY ---- BOM");
2119 content += 3;
2120 length -= 3;
2121 }
2122#endif
2123 if (Tcl_Write(chan, content, length) != length) {
2124 Ns_TclPrintfResult(interp, "could not write %s bytes to %s: %s",
2125 Tcl_GetString(objv[3]),
2126 Tcl_GetString(objv[4]),
2127 Tcl_PosixError(interp));
2128 result = TCL_ERROR1;
2129 }
2130 }
2131 }
2132 }
2133 break;
2134
2135 case CRatelimitIdx:
2136 if (objc > 2) {
2137 int rateLimit, oc = 2;
2138 Ns_ObjvSpec specLength = {"ratelimit", Ns_ObjvInt, &rateLimit, &posintRange0};
2139
2140 if (Ns_ObjvInt(&specLength, interp, &oc, &objv[2]) != TCL_OK0) {
2141 result = TCL_ERROR1;
2142 } else {
2143 connPtr->rateLimit = rateLimit;
2144 }
2145 }
2146 if (result == TCL_OK0) {
2147 Tcl_SetObjResult(interp, Tcl_NewIntObj(connPtr->rateLimit));
2148 }
2149 break;
2150
2151 case CRequestIdx:
2152 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->line, -1));
2153 break;
2154
2155 case CMethodIdx:
2156 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->method, -1));
2157 break;
2158
2159 case CPartialTimesIdx:
2160 {
2161 Ns_Time now, acceptTime, queueTime, filterTime, runTime;
2162 Tcl_DString ds, *dsPtr = &ds;
2163
2164 Ns_GetTime(&now);
2165 Tcl_DStringInit(dsPtr);
2166
2167 (void)Ns_DiffTime(&connPtr->requestQueueTime, &connPtr->acceptTime, &acceptTime);
2168 (void)Ns_DiffTime(&connPtr->requestDequeueTime, &connPtr->requestQueueTime, &queueTime);
2169 (void)Ns_DiffTime(&connPtr->filterDoneTime, &connPtr->requestDequeueTime, &filterTime);
2170 (void)Ns_DiffTime(&now, &connPtr->filterDoneTime, &runTime);
2171
2172 Ns_DStringNAppendTcl_DStringAppend(dsPtr, "accepttime ", 11);
2173 Ns_DStringAppendTime(dsPtr, &acceptTime);
2174
2175 Ns_DStringNAppendTcl_DStringAppend(dsPtr, " queuetime ", 11);
2176 Ns_DStringAppendTime(dsPtr, &queueTime);
2177
2178 Ns_DStringNAppendTcl_DStringAppend(dsPtr, " filtertime ", 12);
2179 Ns_DStringAppendTime(dsPtr, &filterTime);
2180
2181 Ns_DStringNAppendTcl_DStringAppend(dsPtr, " runtime ", 9);
2182 Ns_DStringAppendTime(dsPtr, &runTime);
2183
2184 Tcl_DStringResult(interp, dsPtr);
2185
2186 break;
2187 }
2188
2189 case CProtocolIdx:
2190 Tcl_SetObjResult(interp, Tcl_NewStringObj(connPtr->drvPtr->protocol, -1));
2191 break;
2192
2193 case CHostIdx:
2194 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->host, -1));
2195 break;
2196
2197 case CPortIdx:
2198 Tcl_SetObjResult(interp, Tcl_NewIntObj((int)request->port));
2199 break;
2200
2201 case CUrlIdx:
2202 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->url, request->url_len));
2203 break;
2204
2205 case CQueryIdx:
2206 Tcl_SetObjResult(interp, Tcl_NewStringObj(request->query, -1));
2207 break;
2208
2209 case CUrlcIdx:
2210 Tcl_SetObjResult(interp, Tcl_NewIntObj(request->urlc));
2211 break;
2212
2213 case CVersionIdx:
2214 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(request->version));
2215 break;
2216
2217 case CLocationIdx:
2218 {
2219 Tcl_DString ds;
2220
2221 Ns_DStringInitTcl_DStringInit(&ds);
2222 (void) Ns_ConnLocationAppend(conn, &ds);
2223 Tcl_DStringResult(interp, &ds);
2224 break;
2225 }
2226
2227 case CDriverIdx:
2228 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnDriverName(conn), -1));
2229 break;
2230
2231 case CServerIdx:
2232 Tcl_SetObjResult(interp, Tcl_NewStringObj(Ns_ConnServer(conn), -1));
2233 break;
2234
2235 case CPoolIdx:
2236 Tcl_SetObjResult(interp, Tcl_NewStringObj(connPtr->poolPtr->pool, -1));
2237 break;
2238
2239 case CStatusIdx:
2240 if (objc < 2 || objc > 3) {
2241 Tcl_WrongNumArgs(interp, 2, objv, "?status?");
2242 result = TCL_ERROR1;
2243
2244 } else if (objc == 3) {
2245 Ns_ObjvValueRange statusRange = {100, 599};
2246 int oc = 2, status;
2247 Ns_ObjvSpec spec = {"?status", Ns_ObjvInt, &status, &statusRange};
2248
2249 if (NsConnRequire(interp, NS_CONN_REQUIRE_CONNECTED0x0001u, &conn) != NS_OK) {
2250 result = TCL_ERROR1;
2251
2252 } else if (Ns_ObjvInt(&spec, interp, &oc, &objv[2]) != TCL_OK0) {
2253 result = TCL_ERROR1;
2254
2255 } else {
2256 Tcl_SetObjResult(interp, Tcl_NewIntObj(Ns_ConnResponseStatus(conn)));
2257 Ns_ConnSetResponseStatus(conn, status);
2258 }
2259 } else {
2260 Tcl_SetObjResult(interp, Tcl_NewIntObj(Ns_ConnResponseStatus(conn)));
2261 }
2262 break;
2263
2264 case CTimeoutIdx:
2265 Tcl_SetObjResult(interp, Ns_TclNewTimeObj(Ns_ConnTimeout(conn)));
2266 break;
2267
2268 case CSockIdx:
2269 Tcl_SetObjResult(interp, Tcl_NewIntObj((int)Ns_ConnSock(conn)));
2270 break;
2271
2272 case CIdIdx:
2273 Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)Ns_ConnId(conn)));
2274 break;
2275
2276 case CFlagsIdx:
2277 Tcl_SetObjResult(interp, Tcl_NewIntObj((int)connPtr->flags));
2278 break;
2279
2280 case CStartIdx:
2281 Tcl_SetObjResult(interp, Ns_TclNewTimeObj(&connPtr->requestQueueTime));
2282 break;
2283
2284 case CCloseIdx:
2285 (void) Ns_ConnClose(conn);
2286 break;
2287
2288 case CChannelIdx:
2289 chan = MakeConnChannel(itPtr, conn);
2290 if (chan == NULL((void*)0)) {
2291 result = TCL_ERROR1;
2292 } else {
2293 Tcl_RegisterChannel(interp, chan);
2294 Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan),-1));
2295 }
2296 break;
2297
2298 case CContentSentLenIdx:
2299 if (objc == 2) {
2300 Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)connPtr->nContentSent));
2301
2302 } else if (objc == 3) {
2303 Tcl_WideInt sent;
2304 Ns_ObjvValueRange sentRange = {0, LLONG_MAX9223372036854775807LL};
2305 Ns_ObjvSpec spec = {"?idx", Ns_ObjvWideInt, &sent, &sentRange};
2306 int oc = 1;
2307
2308 if (Ns_ObjvWideInt(&spec, interp, &oc, &objv[2]) != TCL_OK0) {
2309 result = TCL_ERROR1;
2310 } else {
2311 connPtr->nContentSent = (size_t)sent;
2312 }
2313 } else {
2314 Tcl_WrongNumArgs(interp, 2, objv, "?value?");
2315 result = TCL_ERROR1;
2316 }
2317 break;
2318
2319 case CZipacceptedIdx:
2320 Tcl_SetObjResult(interp, Tcl_NewBooleanObj((connPtr->flags & NS_CONN_ZIPACCEPTED) != 0u)Tcl_NewIntObj(((connPtr->flags & 0x10000u) != 0u)!=0));
2321 break;
2322
2323 case CAacceptedcompressionIdx:
2324 {
2325 Tcl_Obj *listObj = Tcl_NewListObj(0, NULL((void*)0));
2326
2327 if ((connPtr->flags & NS_CONN_BROTLIACCEPTED0x20000u) != 0u) {
2328 Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("brotli", 6));
2329 }
2330 if ((connPtr->flags & NS_CONN_ZIPACCEPTED0x10000u) != 0u) {
2331 Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("gzip", 4));
2332 }
2333
2334 Tcl_SetObjResult(interp, listObj);
2335 }
2336 break;
2337
2338 default:
2339 /* unexpected value */
2340 assert(opt && 0)((void) (0));
2341 break;
2342
2343 }
2344
2345 return result;
2346}
2347
2348
2349/*
2350 *----------------------------------------------------------------------
2351 *
2352 * NsTclLocationProcObjCmd --
2353 *
2354 * Implements "ns_locationproc".
2355 *
2356 * Results:
2357 * Tcl result.
2358 *
2359 * Side effects:
2360 * None.
2361 *
2362 *----------------------------------------------------------------------
2363 */
2364
2365int
2366NsTclLocationProcObjCmd(ClientData UNUSED(clientData)UNUSED_clientData __attribute__((__unused__)), Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
2367{
2368 const NsServer *servPtr = NsGetInitServer();
2369 int result = TCL_OK0;
2370
2371 if (objc < 2) {
2372 Tcl_WrongNumArgs(interp, 1, objv, "script ?args?");
2373 result = TCL_ERROR1;
2374
2375 } else if (servPtr == NULL((void*)0)) {
2376 Ns_TclPrintfResult(interp, "no initializing server");
2377 result = TCL_ERROR1;
2378 } else {
2379 Ns_TclCallback *cbPtr = Ns_TclNewCallback(interp, (ns_funcptr_t)NsTclConnLocation,
2380 objv[1], objc - 2, objv + 2);
2381 if (Ns_SetConnLocationProc(NsTclConnLocation, cbPtr) != NS_OK) {
2382 result = TCL_ERROR1;
2383 }
2384 }
2385
2386 return result;
2387}
2388
2389
2390/*
2391 *----------------------------------------------------------------------
2392 *
2393 * NsTclWriteContentObjCmd --
2394 *
2395 * Implements "ns_conncptofp".
2396 *
2397 * Results:
2398 * Standard Tcl result.
2399 *
2400 * Side effects:
2401 * See docs.
2402 *
2403 *----------------------------------------------------------------------
2404 */
2405
2406int
2407NsTclWriteContentObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)
2408{
2409 const NsInterp *itPtr = clientData;
2410 int toCopy = 0, result = TCL_OK0;
2411 char *chanName;
2412 Tcl_Channel chan;
2413
2414 /*
2415 * Syntax: ns_conncptofp ?-bytes tocopy? channel
2416 */
2417
2418 Ns_ObjvSpec opts[] = {
2419 {"-bytes", Ns_ObjvInt, &toCopy, &posintRange0},
2420 {"--", Ns_ObjvBreak, NULL((void*)0), NULL((void*)0)},
2421 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
2422 };
2423 Ns_ObjvSpec args[] = {
2424 {"channel", Ns_ObjvString, &chanName, NULL((void*)0)},
2425 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}
2426 };
2427
2428 if (NsConnRequire(interp, NS_CONN_REQUIRE_ALL0x0007u, NULL((void*)0)) != NS_OK
2429 || Ns_ParseObjv(opts, args, interp, 1, objc, objv) != NS_OK) {
2430 result = TCL_ERROR1;
2431
2432 } else if (GetChan(interp, chanName, &chan) != TCL_OK0) {
2433 result = TCL_ERROR1;
2434
2435 } else if (Tcl_Flush(chan) != TCL_OK0) {
2436 const char *errorMsg = Tcl_ErrnoMsg(Tcl_GetErrno());
2437
2438 Ns_TclPrintfResult(interp, "flush returned error: %s", errorMsg);
2439 Tcl_SetErrorCode(interp, "POSIX", Tcl_ErrnoId(), errorMsg, (char *)0L);
2440 result = TCL_ERROR1;
2441
2442 } else {
2443 const Request *reqPtr = ((Conn *)itPtr->conn)->reqPtr;
2444
2445 Ns_LogDeprecated(objv, 1, "ns_conn copy ...", NULL((void*)0));
2446
2447 if ((toCopy > (int)reqPtr->avail) || (toCopy == 0)) {
2448 toCopy = (int)reqPtr->avail;
2449 }
2450 if (Ns_ConnCopyToChannel(itPtr->conn, (size_t)toCopy, chan) != NS_OK) {
2451 Tcl_SetObjResult(interp, Tcl_NewStringObj("could not copy content", -1));
2452 result = TCL_ERROR1;
2453 }
2454 }
2455
2456 return result;
2457}
2458
2459
2460/*
2461 *----------------------------------------------------------------------
2462 *
2463 * NsTclConnLocation --
2464 *
2465 * Tcl callback to construct location string.
2466 *
2467 * Results:
2468 * dest->string or NULL on error.
2469 *
2470 * Side effects:
2471 * None.
2472 *
2473 *----------------------------------------------------------------------
2474 */
2475
2476char *
2477NsTclConnLocation(Ns_Conn *conn, Ns_DStringTcl_DString *dest, const Ns_TclCallback *cbPtr)
2478{
2479 Tcl_Interp *interp = Ns_GetConnInterp(conn);
2480 char *result;
2481
2482 if (Ns_TclEvalCallback(interp, cbPtr, dest, (char *)0L) != TCL_OK0) {
2483 (void) Ns_TclLogErrorInfo(interp, "\n(context: location callback)");
2484 result = NULL((void*)0);
2485 } else {
2486 result = Ns_DStringValue(dest)((dest)->string);
2487 }
2488 return result;
2489}
2490
2491
2492/*
2493 *----------------------------------------------------------------------
2494 *
2495 * GetChan --
2496 *
2497 * Return an open channel.
2498 *
2499 * Results:
2500 * TCL_OK if given a valid channel id, TCL_ERROR otherwise.
2501 *
2502 * Side effects:
2503 * Channel is set in given chanPtr or error message left in
2504 * given interp.
2505 *
2506 *----------------------------------------------------------------------
2507 */
2508
2509static int
2510GetChan(Tcl_Interp *interp, const char *id, Tcl_Channel *chanPtr)
2511{
2512 Tcl_Channel chan;
2513 int mode, result = TCL_OK0;
2514
2515 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
2516 NS_NONNULL_ASSERT(id != NULL)((void) (0));
2517 NS_NONNULL_ASSERT(chanPtr != NULL)((void) (0));
2518
2519 chan = Tcl_GetChannel(interp, id, &mode);
2520 if (chan == (Tcl_Channel) NULL((void*)0)) {
2521 result = TCL_ERROR1;
2522
2523 } else if ((mode & TCL_WRITABLE(1<<2)) == 0) {
2524 Ns_TclPrintfResult(interp, "channel \"%s\" wasn't opened for writing", id);
2525 result = TCL_ERROR1;
2526
2527 } else {
2528 *chanPtr = chan;
2529 }
2530
2531 return result;
2532}
2533
2534
2535/*----------------------------------------------------------------------------
2536 *
2537 * MakeConnChannel --
2538 *
2539 * Wraps a Tcl channel around the current connection socket
2540 * and returns the channel handle to the caller.
2541 *
2542 * Result:
2543 * Tcl_Channel handle or NULL.
2544 *
2545 * Side Effects:
2546 * Removes the socket from the connection structure.
2547 *
2548 *----------------------------------------------------------------------------
2549 */
2550
2551static Tcl_Channel
2552MakeConnChannel(const NsInterp *itPtr, Ns_Conn *conn)
2553{
2554 Conn *connPtr;
2555 Tcl_Channel chan = NULL((void*)0);
2556
2557 NS_NONNULL_ASSERT(conn != NULL)((void) (0));
2558 NS_NONNULL_ASSERT(itPtr != NULL)((void) (0));
2559
2560 connPtr = (Conn *) conn;
2561 if (unlikely((connPtr->flags & NS_CONN_CLOSED) != 0u)(__builtin_expect(((connPtr->flags & 0x001u) != 0u), 0
))
) {
2562 Ns_TclPrintfResult(itPtr->interp, "connection closed");
2563
2564 } else {
2565
2566 assert(connPtr->sockPtr != NULL)((void) (0));
2567 if (connPtr->sockPtr->sock == NS_INVALID_SOCKET(-1)) {
2568 Ns_TclPrintfResult(itPtr->interp, "no socket for connection");
2569
2570 } else {
2571
2572 /*
2573 * Create Tcl channel around the connection socket
2574 */
2575
2576 chan = Tcl_MakeTcpClientChannel(NSSOCK2PTR(connPtr->sockPtr->sock)((void *)(intptr_t)(connPtr->sockPtr->sock)));
2577 if (unlikely(chan == NULL)(__builtin_expect((chan == ((void*)0)), 0))) {
2578 Ns_TclPrintfResult(itPtr->interp, "%s", Tcl_PosixError(itPtr->interp));
2579
2580 } else {
2581 /*
2582 * Disable keep-alive and chunking headers.
2583 */
2584
2585 if (connPtr->responseLength < 0) {
2586 connPtr->keep = (int)NS_FALSE0;
2587 }
2588
2589 /*
2590 * Check to see if HTTP headers are required and flush
2591 * them now before the conn socket is dissociated.
2592 */
2593
2594 if ((conn->flags & NS_CONN_SENTHDRS0x010u) == 0u) {
2595 if ((itPtr->nsconn.flags & CONN_TCLHTTP0x10u) == 0u) {
2596 conn->flags |= NS_CONN_SKIPHDRS0x002u;
2597 } else {
2598 if (Ns_ConnWriteVData(conn, NULL((void*)0), 0, NS_CONN_STREAM0x040u) != NS_OK) {
2599 Ns_Log(Error, "make channel: error writing headers");
2600 }
2601 }
2602 }
2603
2604 if (Ns_SockSetBlocking(connPtr->sockPtr->sock) != NS_OK) {
2605 Ns_Log(Error, "make channel: error while making channel blocking");
2606 }
2607
2608 connPtr->sockPtr->sock = NS_INVALID_SOCKET(-1);
2609 }
2610 }
2611 }
2612
2613 return chan;
2614}
2615
2616/*
2617 *----------------------------------------------------------------------
2618 *
2619 * NsConnRequire --
2620 *
2621 * Return the conn for the given interp, in case it is fully functioning.
2622 * In case that interp is
2623 *
2624 * - not connected at all (e.g. no connection thread), or
2625 * - when the sockPtr of the connection was detachted, or
2626 * - when the connection is already closed,
2627 *
2628 * return NS_ERROR and set an appropriate error message, If connPtr is
2629 * valid, the function return NS_OK and returns the connPtr in its second
2630 * argument.
2631 *
2632 * Results:
2633 * NaviServer result code
2634 *
2635 * Side effects:
2636 * Sets Tcl result on error.
2637 *
2638 *----------------------------------------------------------------------
2639 */
2640
2641Ns_ReturnCode
2642NsConnRequire(Tcl_Interp *interp, unsigned int flags, Ns_Conn **connPtr)
2643{
2644 Ns_Conn *conn;
2645 Ns_ReturnCode status;
2646
2647 NS_NONNULL_ASSERT(interp != NULL)((void) (0));
2648
2649 conn = Ns_TclGetConn(interp);
2650 if (conn == NULL((void*)0)) {
2651 Tcl_SetObjResult(interp, Tcl_NewStringObj("no connection", -1));
2652 status = NS_ERROR;
2653
2654 } else if (((flags & NS_CONN_REQUIRE_CONNECTED0x0001u) != 0u)
2655 && (Ns_ConnSockPtr(conn) == NULL((void*)0))) {
2656 Tcl_SetObjResult(interp, Tcl_NewStringObj("connection socket is detached", -1));
2657 status = NS_ERROR;
2658
2659 } else if (((flags & NS_CONN_REQUIRE_OPEN0x0002u) != 0u)
2660 && ((conn->flags & NS_CONN_CLOSED0x001u) != 0u)
2661 && nsconf.reject_already_closed_connection) {
2662 Tcl_SetObjResult(interp, Tcl_NewStringObj("connection already closed", -1));
2663 status = NS_ERROR;
2664
2665 } else if (((flags & NS_CONN_REQUIRE_CONFIGURED0x0004u) != 0u)
2666 && ((conn->flags & NS_CONN_CONFIGURED0x1000000u) == 0u)) {
2667 Tcl_SetObjResult(interp, Tcl_NewStringObj("connection is not configured", -1));
2668 status = NS_ERROR;
2669
2670 } else {
2671 if (connPtr != NULL((void*)0)) {
2672 *connPtr = conn;
2673 }
2674 status = NS_OK;
2675 }
2676
2677 return status;
2678}
2679
2680
2681/*
2682 * Local Variables:
2683 * mode: c
2684 * c-basic-offset: 4
2685 * fill-column: 78
2686 * indent-tabs-mode: nil
2687 * End:
2688 */