Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Preliminary support for SCGI in althttpd. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | althttpd-scgi |
Files: | files | file ages | folders |
SHA3-256: |
b3aaed91bab3f1ae32bab40ceddba152 |
User & Date: | drh 2019-02-15 20:14:40.760 |
Context
2019-02-15
| ||
20:27 | Updates to comments. Use size_t instead of int where appropriate. (check-in: 5faf086850 user: drh tags: althttpd-scgi) | |
20:14 | Preliminary support for SCGI in althttpd. (check-in: b3aaed91ba user: drh tags: althttpd-scgi) | |
18:16 | In althttpd.c, refactor some of the CGI processing logic as a preliminary step toward adding SCGI support. (check-in: 3e667aef3a user: drh tags: trunk) | |
Changes
Changes to misc/althttpd.c.
︙ | ︙ | |||
260 261 262 263 264 265 266 | static int standalone = 0; /* Run as a standalone server (no inetd) */ static int ipv6Only = 0; /* Use IPv6 only */ static int ipv4Only = 0; /* Use IPv4 only */ static struct rusage priorSelf; /* Previously report SELF time */ static struct rusage priorChild; /* Previously report CHILD time */ static int mxAge = 120; /* Cache-control max-age */ static char *default_path = "/bin:/usr/bin"; /* Default PATH variable */ | < > < < | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | static int standalone = 0; /* Run as a standalone server (no inetd) */ static int ipv6Only = 0; /* Use IPv6 only */ static int ipv4Only = 0; /* Use IPv4 only */ static struct rusage priorSelf; /* Previously report SELF time */ static struct rusage priorChild; /* Previously report CHILD time */ static int mxAge = 120; /* Cache-control max-age */ static char *default_path = "/bin:/usr/bin"; /* Default PATH variable */ /* ** Mapping between CGI variable names and values stored in ** global variables. */ static struct { char *zEnvName; char **pzEnvValue; } cgienv[] = { { "CONTENT_LENGTH", &zContentLength }, /* Must be first for SCGI */ { "AUTH_TYPE", &zAuthType }, { "AUTH_CONTENT", &zAuthArg }, { "CONTENT_TYPE", &zContentType }, { "DOCUMENT_ROOT", &zHome }, { "HTTP_ACCEPT", &zAccept }, { "HTTP_ACCEPT_ENCODING", &zAcceptEncoding }, { "HTTP_COOKIE", &zCookie }, { "HTTP_HOST", &zHttpHost }, { "HTTP_IF_MODIFIED_SINCE", &zIfModifiedSince }, { "HTTP_IF_NONE_MATCH", &zIfNoneMatch }, { "HTTP_REFERER", &zReferer }, |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 | } aRes[nRes] = 0; nOut += printf("Content-length: %d\r\n\r\n%s", nRes, aRes); free(aRes); } fclose(in); } /* ** This routine processes a single HTTP request on standard input and ** sends the reply to standard output. If the argument is 1 it means ** that we are should close the socket without processing additional ** HTTP requests after the current request finishes. 0 means we are ** allowed to keep the connection open and to process additional requests. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 | } aRes[nRes] = 0; nOut += printf("Content-length: %d\r\n\r\n%s", nRes, aRes); free(aRes); } fclose(in); } /* ** Send an SCGI request to a host identified by zFile and process the ** reply. */ static void SendScgiRequest(const char *zFile, const char *zScript){ FILE *in; FILE *s; char *z; char *zHost; char *zPort = 0; int rc; int iSocket = -1; struct addrinfo hints; struct addrinfo *ai = 0; struct addrinfo *p; char *zHdr; int nHdr = 0; int nHdrAlloc; int i; char zLine[1000]; in = fopen(zFile, "rb"); if( in==0 ){ Malfunction(700, "cannot open \"%s\"\n", zFile); } if( fgets(zLine, sizeof(zLine)-1, in)==0 ){ Malfunction(701, "cannot read \"%s\"\n", zFile); } fclose(in); if( strncmp(zLine,"SCGI ",5)!=0 ){ Malfunction(702, "misformatted SCGI spec \"%s\"\n", zFile); } z = zLine+5; zHost = GetFirstElement(z,&z); zPort = GetFirstElement(z,0); if( zHost==0 || zPort==0 ){ Malfunction(703, "misformatted SCGI spec \"%s\"\n", zFile); } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; rc = getaddrinfo(zHost,zPort,&hints,&ai); if( rc ){ Malfunction(704, "cannot resolve SCGI server name %s:%s\n%s\n", zHost, zPort, gai_strerror(rc)); } for(p=ai; p; p=p->ai_next){ iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if( iSocket<0 ) continue; if( connect(iSocket,p->ai_addr,p->ai_addrlen)>=0 ) break; close(iSocket); } if( iSocket<0 ){ Malfunction(705, "cannot open socket to SCGI server %s\n", zScript); } s = fdopen(iSocket, "r+"); if( s==0 ){ Malfunction(706, "could not turn the socket into a FILE\n"); } nHdrAlloc = 0; zHdr = 0; if( zContentLength==0 ) zContentLength = "0"; for(i=0; i<sizeof(cgienv)/sizeof(cgienv[0]); i++){ int n1, n2; if( cgienv[i].pzEnvValue[0]==0 ) continue; n1 = (int)strlen(cgienv[i].zEnvName); n2 = (int)strlen(*cgienv[i].pzEnvValue); if( n1+n2+2+nHdr >= nHdrAlloc ){ nHdrAlloc = nHdr + n1 + n2 + 1000; zHdr = realloc(zHdr, nHdrAlloc); if( zHdr==0 ){ Malfunction(706, "out of memory"); } } memcpy(zHdr+nHdr, cgienv[i].zEnvName, n1); nHdr += n1; zHdr[nHdr++] = 0; memcpy(zHdr+nHdr, *cgienv[i].pzEnvValue, n2); nHdr += n2; zHdr[nHdr++] = 0; } fprintf(s,"%d:",nHdr); fwrite(zHdr, 1, nHdr, s); fprintf(s,","); free(zHdr); if( zMethod[0]=='P' && atoi(zContentLength)>0 && (in = fopen(zTmpNam,"r"))!=0 ){ size_t n; while( (n = fread(zLine,1,sizeof(zLine),in))>0 ){ fwrite(zLine, 1, n, s); } fclose(in); } fflush(s); CgiHandleReply(s); } /* ** This routine processes a single HTTP request on standard input and ** sends the reply to standard output. If the argument is 1 it means ** that we are should close the socket without processing additional ** HTTP requests after the current request finishes. 0 means we are ** allowed to keep the connection open and to process additional requests. |
︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 1689 | */ sprintf(zLine, "%s/-auth", zDir); if( access(zLine,R_OK)==0 && !CheckBasicAuthorization(zLine) ) return; /* Take appropriate action */ if( (statbuf.st_mode & 0100)==0100 && access(zFile,X_OK)==0 ){ /* | > > < | > < > > > > > > > > < < < < < < < < < < | | 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 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 | */ sprintf(zLine, "%s/-auth", zDir); if( access(zLine,R_OK)==0 && !CheckBasicAuthorization(zLine) ) return; /* Take appropriate action */ if( (statbuf.st_mode & 0100)==0100 && access(zFile,X_OK)==0 ){ char *zBaseFilename; /* Filename without directory prefix */ /* ** Abort with an error if the CGI script is writable by anyone other ** than its owner. */ if( statbuf.st_mode & 0022 ){ CgiScriptWritable(); } /* If its executable, it must be a CGI program. Start by ** changing directories to the directory holding the program. */ if( chdir(zDir) ){ char zBuf[1000]; Malfunction(420, /* LOG: chdir() failed */ "cannot chdir to [%s] from [%s]", zDir, getcwd(zBuf,999)); } /* Compute the base filename of the CGI script */ for(i=strlen(zFile)-1; i>=0 && zFile[i]!='/'; i--){} zBaseFilename = &zFile[i+1]; /* Setup the environment appropriately. */ putenv("GATEWAY_INTERFACE=CGI/1.0"); for(i=0; i<(int)(sizeof(cgienv)/sizeof(cgienv[0])); i++){ if( *cgienv[i].pzEnvValue ){ SetEnv(cgienv[i].zEnvName,*cgienv[i].pzEnvValue); } } if( useHttps ){ putenv("HTTPS=on"); } /* For the POST method all input has been written to a temporary file, ** so we have to redirect input to the CGI script from that file. */ if( zMethod[0]=='P' ){ if( dup(0)<0 ){ Malfunction(430, /* LOG: dup(0) failed */ "Unable to duplication file descriptor 0"); } close(0); open(zTmpNam, O_RDONLY); } if( strncmp(zBaseFilename,"nph-",4)==0 ){ /* If the name of the CGI script begins with "nph-" then we are ** dealing with a "non-parsed headers" CGI script. Just exec() ** it directly and let it handle all its own header generation. */ execl(zBaseFilename,zBaseFilename,(char*)0); /* NOTE: No log entry written for nph- scripts */ exit(0); |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 | in = fdopen(px[0], "rb"); } if( in==0 ){ CgiError(); }else{ CgiHandleReply(in); } }else if( countSlashes(zRealScript)!=countSlashes(zScript) ){ /* If the request URI for static content contains material past the ** actual content file name, report that as a 404 error. */ NotFound(460); /* LOG: Excess URI content past static file name */ }else{ /* If it isn't executable then it ** must a simple file that needs to be copied to output. | > > > > > > > | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | in = fdopen(px[0], "rb"); } if( in==0 ){ CgiError(); }else{ CgiHandleReply(in); } }else if( lenFile>5 && strcmp(&zFile[lenFile-5],".scgi")==0 ){ /* Any file that ends with ".scgi" is assumed to be text of the ** form: ** SCGI hostname port ** Open a TCP/IP connection to that host and send it an SCGI request */ SendScgiRequest(zFile, zScript); }else if( countSlashes(zRealScript)!=countSlashes(zScript) ){ /* If the request URI for static content contains material past the ** actual content file name, report that as a 404 error. */ NotFound(460); /* LOG: Excess URI content past static file name */ }else{ /* If it isn't executable then it ** must a simple file that needs to be copied to output. |
︙ | ︙ |