Changes On Branch ashish-ipv6
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch ashish-ipv6 Excluding Merge-Ins

This is equivalent to a diff from 8a8177071f to 26b7b16a7c

2014-11-11
20:25
Update to the 3.8.8 alpha of SQLite for testing (of SQLite). check-in: 6b2f0b209f user: drh tags: trunk
18:22
Merge the latest changes from trunk. check-in: 73b8c619ee user: drh tags: tk-diff-viewer
12:15
Merge from trunk Closed-Leaf check-in: 26b7b16a7c user: ashish tags: ashish-ipv6
2014-11-10
02:41
Update the makefile.wiki documentation page to talk about the mkbuiltin.exe program used for generating the builtin_data.h header file. check-in: 8a8177071f user: drh tags: trunk
2014-11-09
20:04
Same change a previous commit, but for custom makefile check-in: ee5b864898 user: jan.nijtmans tags: trunk
2014-07-20
13:20
Merge from trunk check-in: c4fca467f7 user: ashish tags: ashish-ipv6

Changes to auto.def.
14
15
16
17
18
19
20

21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28







+







    with-tcl-private-stubs=0
                         => {Enable Tcl integration via private stubs mechanism}
    internal-sqlite=1    => {Don't use the internal SQLite, use the system one}
    static=0             => {Link a static executable}
    lineedit=1           => {Disable line editing}
    fusefs=1             => {Disable the Fuse Filesystem}
    fossil-debug=0       => {Build with fossil debugging enabled}
    ipv6=1		 => {Disable IPv6 support}
    json=0               => {Build with fossil JSON API enabled}
}

# sqlite wants these types if possible
cc-with {-includes {stdint.h inttypes.h}} {
    cc-check-types uint32_t uint16_t int16_t uint8_t
}
106
107
108
109
110
111
112




















113
114
115
116
117
118
119
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#}

if {[opt-bool static]} {
    # XXX: This will not work on all systems.
    define-append EXTRA_LDFLAGS -static
    msg-result "Trying to link statically"
}

if {[opt-bool ipv6]} {
   define-append EXTRA_CFLAGS -DWITH_IPV6
   msg-result "IPv6 support enabled"
   if {[cc-check-functions getaddrinfo]} {
      define-append EXTRA_CFLAGS -DHAVE_GETADDRINFO
      msg-result "getaddrinfo() enabled"
   }
}

# Check for zlib, using the given location if specified
set zlibpath [opt-val with-zlib]
if {$zlibpath ne ""} {
    cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
    define-append EXTRA_CFLAGS -I$zlibpath
    define-append EXTRA_LDFLAGS -L$zlibpath
}
if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
    user-error "zlib not found please install it or specify the location with --with-zlib"
}

set tclpath [opt-val with-tcl]
if {$tclpath ne ""} {
    set tclprivatestubs [opt-bool with-tcl-private-stubs]
    # Note parse-tclconfig-sh is in autosetup/local.tcl
    if {$tclpath eq "1"} {
        if {$tclprivatestubs} {
Changes to src/cgi.c.
29
30
31
32
33
34
35

36
37
38
39
40
41
42
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43







+







# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <sys/times.h>
# include <sys/time.h>
# include <sys/wait.h>
# include <sys/select.h>
# include <netdb.h>             /* for NI_NUMERICHOST */
#endif
#ifdef __EMX__
  typedef int socklen_t;
#endif
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
1266
1267
1268
1269
1270
1271
1272
1273
1274


1275
1276
1277
1278
1279
1280
1281
1267
1268
1269
1270
1271
1272
1273


1274
1275
1276
1277
1278
1279
1280
1281
1282







-
-
+
+







** environment variables.  A call to cgi_init() completes
** the setup.  Once all the setup is finished, this procedure returns
** and subsequent code handles the actual generation of the webpage.
*/
void cgi_handle_http_request(const char *zIpAddr){
  char *z, *zToken;
  int i;
  struct sockaddr_in remoteName;
  socklen_t size = sizeof(struct sockaddr_in);
  struct sockaddr_storage remoteName;
  socklen_t size = sizeof(remoteName);
  char zLine[2000];     /* A single line of input. */
  g.fullHttpReply = 1;
  if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
    malformed_request("missing HTTP header");
  }
  blob_append(&g.httpHeader, zLine, -1);
  cgi_trace(zLine);
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1296
1297
1298
1299
1300
1301
1302










1303
1304
1305
1306
1307
1308
1309







-
-
-
-
-
-
-
-
-
-







  }
  cgi_setenv("REQUEST_URI", zToken);
  cgi_setenv("SCRIPT_NAME", "");
  for(i=0; zToken[i] && zToken[i]!='?'; i++){}
  if( zToken[i] ) zToken[i++] = 0;
  cgi_setenv("PATH_INFO", zToken);
  cgi_setenv("QUERY_STRING", &zToken[i]);
  if( zIpAddr==0 &&
        getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
                                &size)>=0
  ){
    zIpAddr = inet_ntoa(remoteName.sin_addr);
  }
  if( zIpAddr ){
    cgi_setenv("REMOTE_ADDR", zIpAddr);
    g.zIpAddr = mprintf("%s", zIpAddr);
  }

  /* Get all the optional fields that follow the first line.
  */
  while( fgets(zLine,sizeof(zLine),g.httpIn) ){
    char *zFieldName;
    char *zVal;

1351
1352
1353
1354
1355
1356
1357



























1358
1359
1360
1361
1362
1363
1364
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      const char *zIpAddr = cgi_accept_forwarded_for(zVal);
      if( zIpAddr!=0 ){
        g.zIpAddr = mprintf("%s", zIpAddr);
        cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
      }
    }
  }

  if( zIpAddr==0 &&
      getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, 
                                &size)>=0
  ){
    sa_family_t family;
    int v4mapped=0;
    if( remoteName.ss_family == AF_INET6 && 
        IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6*)&remoteName)->sin6_addr)) ){
        v4mapped = 1;
    }
    if(!getnameinfo((struct sockaddr*)&remoteName, size, zLine, sizeof(zLine),
                    NULL, 0, NI_NUMERICHOST)){
      zIpAddr = zLine;
    } else {
      zIpAddr = NULL;
    }
    if(zIpAddr && v4mapped) {
      /* ::ffff:172.16.0.2 */
      zIpAddr += 7; 
    }
  }
  if( zIpAddr ){
    cgi_setenv("REMOTE_ADDR", zIpAddr);
    g.zIpAddr = mprintf("%s", zIpAddr);
  }

  cgi_init();
  cgi_trace(0);
}

/*
** This routine handles a single HTTP request from an SSH client which is
** coming in on g.httpIn and which replies on g.httpOut
1662
1663
1664
1665
1666
1667
1668











1669


1670
1671
1672
1673

1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688






































1689
1690
1691


1692














































1693
1694
1695






1696



1697
1698
1699
1700

1701
1702
1703
1704
1705
1706
1707
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705















1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804

1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819







+
+
+
+
+
+
+
+
+
+
+

+
+




+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
+
+
+
+
+
-
+
+
+




+







  int listener = -1;           /* The server socket */
  int connection;              /* A socket for each individual connection */
  fd_set readfds;              /* Set of file descriptors for select() */
  socklen_t lenaddr;           /* Length of the inaddr structure */
  int child;                   /* PID of the child process */
  int nchildren = 0;           /* Number of child processes */
  struct timeval delay;        /* How long to wait inside select() */
#ifdef HAVE_GETADDRINFO
  struct addrinfo hints;
  struct addrinfo* res;
  struct addrinfo* i;
  struct sockaddr_storage inaddr;   /* The socket address */
  char* sPort;
  int iRet;
#else // HAVE_GETADDRINFO
#ifdef WITH_IPV6
  struct sockaddr_storage inaddr;   /* The socket address */
#else  // WITH_IPV6
  struct sockaddr_in inaddr;   /* The socket address */
#endif // WITH_IPV6
#endif // HAVE_GETADDRINFO
  int opt = 1;                 /* setsockopt flag */
  int iPort = mnPort;

  while( iPort<=mxPort ){
#ifdef HAVE_GETADDRINFO
    memset(&inaddr, 0, sizeof(inaddr));
    inaddr.sin_family = AF_INET;
    if( zIpAddr ){
      inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
      if( inaddr.sin_addr.s_addr == (-1) ){
        fossil_fatal("not a valid IP address: %s", zIpAddr);
      }
    }else if( flags & HTTP_SERVER_LOCALHOST ){
      inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    }else{
      inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    }
    inaddr.sin_port = htons(iPort);
    listener = socket(AF_INET, SOCK_STREAM, 0);
    if( listener<0 ){
    memset(&hints, 0, sizeof(struct addrinfo));
#ifdef WITH_IPV6
    hints.ai_family = PF_UNSPEC;
#else  // WITH_IPV6
    hints.ai_family = PF_INET;
#endif // WITH_IPV6
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    if(!(flags & HTTP_SERVER_LOCALHOST)) hints.ai_flags |= AI_PASSIVE;

    sPort = mprintf("%d", iPort);

    if(iRet = getaddrinfo(NULL, sPort, &hints, &res)) {
      fossil_fatal("Unable to obtain address: %s", gai_strerror(iRet));
    }

    for(i = res; i; i = i->ai_next) {
      listener = socket(i->ai_family, i->ai_socktype, i->ai_protocol);
      if(listener < 0) {
        fossil_fatal("Unable to create socket");
      }
	  opt=1;
      setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
      if(i->ai_family == AF_INET6) {
        opt=0;
        setsockopt(listener, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
      }
      if( bind(listener, i->ai_addr, i->ai_addrlen)<0 ){
        close(listener);
        listener = -1;
      }
	  break;
    }

    free(sPort);
    freeaddrinfo(res);

    if(listener == -1) {
      iPort++;
      continue;
    }
#else // HAVE_GETADDRINFO
    memset(&inaddr, 0, sizeof(inaddr));

    if( zIpAddr ){
#ifdef WITH_IPV6
      ((struct sockaddr_in6*)&inaddr)->sin6_family = AF_INET6;
      if( inet_pton(AF_INET6, argv[1], &((struct sockaddr_in6*)&inaddr)->sin6_addr) < 1 ){
        ((struct sockaddr_in*)&inaddr)->sin_family = AF_INET;
      	((struct sockaddr_in*)&inaddr)->sin_addr.s_addr = inet_addr(zIpAddr);
        if( ((struct sockaddr_in*)&inaddr)->sin_addr.s_addr  == (-1) )
#else // WITH_IPV6
      inaddr.sin_family = AF_INET;
      inaddr.sin_addr.s_addr = inet_addr(zIpAddr);
      if( inaddr.sin_addr.s_addr == (-1) )
#endif // WITH_IPV6
      {
        fossil_fatal("not a valid IP address: %s", zIpAddr);
      }
#ifdef WITH_IPV6
    }
#endif // WITH_IPV6
    }else if( flags & HTTP_SERVER_LOCALHOST ){
#ifdef WITH_IPV6
      memcpy(&((struct sockaddr_in6*)&inaddr)->sin6_addr, &in6addr_loopback, sizeof(inaddr.sin6_addr));
#else  // WITH_IPV6
      inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
#endif // WITH_IPV6
    }else{
#ifdef WITH_IPV6
      memcpy(&((struct sockaddr_in6*)&inaddr)->sin6_addr, &in6addr_any, sizeof(inaddr.sin6_addr));
#else  // WITH_IPV6
      inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
#endif // WITH_IPV6
    }
#ifdef WITH_IPV6
    if( inaddr.ss_family == AF_INET6 ){
      ((struct sockaddr_in6*)&inaddr)->sin6_port = htons(iPort);
    }else{
      ((struct sockaddr_in*)&inaddr)->sin_port = htons(iPort);
    }
    listener = socket(inaddr.ss_family, SOCK_STREAM, 0);
#else // WITH_IPV6
    inaddr.sin_port = htons(iPort);
    listener = socket(AF_INET, SOCK_STREAM, 0);
#endif // WITH_IPV6
    if( listener<0 ){
      fossil_fatal("Unable to create socket");
    }

    /* if we can't terminate nicely, at least allow the socket to be reused */
    setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

#ifdef WITH_IPV6
    opt=0;
    setsockopt(listener, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));

    if( bind(listener, (struct sockaddr*)&inaddr, inaddr.ss_family == AF_INET6 ? sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)) < 0 )
#else // WITH_IPV6
    if( bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr))<0 ){
    if( bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0 )
#endif // WITH_IPV6
	{
      close(listener);
      iPort++;
      continue;
    }
#endif // HAVE_GETADDRINFO
    break;
  }
  if( iPort>mxPort ){
    if( mnPort==mxPort ){
      fossil_fatal("unable to open listening socket on ports %d", mnPort);
    }else{
      fossil_fatal("unable to open listening socket on any"
1770
1771
1772
1773
1774
1775
1776
1777

1778
1779
1780
1781
1782
1783
1784
1882
1883
1884
1885
1886
1887
1888

1889
1890
1891
1892
1893
1894
1895
1896







-
+







    /* Bury dead children */
    while( waitpid(0, 0, WNOHANG)>0 ){
      nchildren--;
    }
  }
  /* NOT REACHED */
  fossil_exit(1);
#endif
#endif // WIN32
  /* NOT REACHED */
  return 0;
}


/*
** Name of days and months.
Changes to src/http_socket.c.
130
131
132
133
134
135
136
















































137
138
139
140
141
142
143
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







**
**    pUrlDAta->name       Name of the server.  Ex: www.fossil-scm.org
**    pUrlDAta->port       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
  int error = 0;
#ifdef HAVE_GETADDRINFO
  struct addrinfo hints;
  struct addrinfo* res;
  struct addrinfo* i;
  char ip[INET6_ADDRSTRLEN];
  void* addr;
  char* sPort;

  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_flags = AI_ADDRCONFIG;
#ifdef WITH_IPV6
  hints.ai_family = PF_UNSPEC;
#else
  hints.ai_family = PF_INET;
#endif
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;

  sPort = mprintf("%d", pUrlData->port);

  if(getaddrinfo(pUrlData->name, sPort, &hints, &res)) {
    socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
    free(sPort);
    return 1;
  }
  for(i = res; i; i = i->ai_next) {
    iSocket = socket(i->ai_family, i->ai_socktype, i->ai_protocol);
    if(iSocket < 0) {
      continue;
    }
    if(connect(iSocket, i->ai_addr, i->ai_addrlen) < 0) {
      close(iSocket);
      iSocket = -1;
      continue;
    }
    if(!getnameinfo(i->ai_addr, i->ai_addrlen, ip, sizeof(ip),
                    NULL, 0, NI_NUMERICHOST))
        g.zIpAddr = mprintf("%s", ip);
    break;
  }
  if(iSocket == -1) {
    socket_set_errmsg("cannot connect to host %s:%s", pUrlData->name, sPort);
    error = 1;
  }
  free(sPort);
  freeaddrinfo(res);
#else
  static struct sockaddr_in addr;  /* The server address */
  static int addrIsInit = 0;       /* True once addr is initialized */

  socket_global_init();
  if( !addrIsInit ){
    addr.sin_family = AF_INET;
    addr.sin_port = htons(pUrlData->port);
168
169
170
171
172
173
174
175

176

177

178

179
180

181
182
183
184
185
186
187
216
217
218
219
220
221
222

223
224
225
226
227

228
229

230
231
232
233
234
235
236
237







-
+

+

+
-
+

-
+







    socket_set_errmsg("cannot create a socket");
    return 1;
  }
  if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
    socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
                      pUrlData->port);
    socket_close();
    return 1;
    error = 1;
  }
#endif
#if !defined(_WIN32)
  if(!error)
  signal(SIGPIPE, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
#endif
  return 0;
  return error;
}

/*
** Send content out over the open socket connection.
*/
size_t socket_send(void *NotUsed, void *pContent, size_t N){
  size_t sent;
Changes to src/login.c.
810
811
812
813
814
815
816

817
818
819
820
821
822
823
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824







+







  ** then there is no need to check user credentials.
  **
  ** This feature allows the "fossil ui" command to give the user
  ** full access rights without having to log in.
  */
  zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
  if( ( fossil_strcmp(zIpAddr, "127.0.0.1")==0 ||
        fossil_strcmp(zIpAddr, "::1")==0 ||
        g.fSshClient & CGI_SSH_CLIENT )
   && g.useLocalauth
   && db_get_int("localauth",0)==0
   && P("HTTPS")==0
  ){
    if( g.localOpen ) zLogin = db_lget("default-user",0);
    if( zLogin!=0 ){
Changes to src/main.c.
148
149
150
151
152
153
154

155
156
157
158
159
160
161
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162







+







  int fSshTrace;          /* Trace the SSH setup traffic */
  int fSshClient;         /* HTTP client flags for SSH client */
  char *zSshCmd;          /* SSH command string */
  int fNoSync;            /* Do not do an autosync ever.  --nosync */
  char *zPath;            /* Name of webpage being served */
  char *zExtra;           /* Extra path information past the webpage name */
  char *zBaseURL;         /* Full text of the URL being served */
  char *zRedirectBaseURL; /* Full text of the URL being served to be used in redirect */
  char *zTop;             /* Parent directory of zPath */
  const char *zContentType;  /* The content type of the input HTTP request */
  int iErrPriority;       /* Priority of current error message */
  char *zErrMsg;          /* Text of an error message */
  int sslNotAvailable;    /* SSL is not available.  Do not redirect to https: */
  Blob cgiIn;             /* Input to an xfer www method */
  int cgiOutput;          /* Write error and status messages to CGI */
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2099
2100
2101
2102
2103
2104
2105

2106
2107
2108
2109
2110
2111
2112







-







** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by setting turning off the
** "localauth" setting.  Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off
** and the connection is from localhost.  The optional REPOSITORY argument
** to "ui" may be a directory and will function as "server" if and only if
** the --notfound option is used.
**
** Options:
**   --localauth         enable automatic login for requests from localhost
**   --localhost         listen on 127.0.0.1 only (always true for "ui")
**   -P|--port TCPPORT   listen to request on port TCPPORT
**   --th-trace          trace TH1 execution (for debugging purposes)
**   --baseurl URL       Use URL as the base (useful for reverse proxies)
**   --notfound URL      Redirect
2191
2192
2193
2194
2195
2196
2197

2198
2199
2200
2201
2202
2203
2204
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205







+







          break;
        }
      }
    }
#else
    zBrowser = db_get("web-browser", "open");
#endif
    zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
    if( zIpAddr ){
      zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
    }else{
      zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
    }
    if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
    if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;