コード例 #1
0
ファイル: network.cpp プロジェクト: Philldomd/UNIX-Lab2
Network::Err Network::handleConnection(SocketData* conn)
{
	int connSock = conn->fd;
	char* buffer = conn->readBuf;
	size_t toRead = readBufSize - conn->readLen;
	ssize_t receivedBytes = recv(connSock, buffer + conn->readLen, toRead, 0);
	if (receivedBytes == -1)
	{
		Log::err("recv(): %s", strerror(errno));
		if (close(connSock) == -1)
		{
			Log::err("close(): %s", strerror(errno));
		}
		return Err::Process;
	}
	else if (receivedBytes == 0)
	{
		Log::info("Closing disconnected socket");
		if (close(connSock) == -1)
		{
			Log::err("close(): %s", strerror(errno));
		}
		return Err::Process;
	}
	
	conn->readLen += receivedBytes;
	receivedBytes = conn->readLen;
	
	if (strnstr(buffer, "\r\n\r\n", receivedBytes) == nullptr
		&& strnstr(buffer, "\r\r", receivedBytes) == nullptr
		&& strnstr(buffer, "\n\n", receivedBytes) == nullptr)
	{
		if (receivedBytes == readBufSize)
		{
			if (close(connSock) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			return Err::Process;
		}
		
		return Err::ReadMore;
	}
	
	char* rPos = (char*)memchr(buffer, '\r', receivedBytes);
	char* nPos = (char*)memchr(buffer, '\n', receivedBytes);
	
	char* lineEndPos = nPos;
	if (nPos == nullptr || (rPos != nullptr && rPos < nPos))
	{
		lineEndPos = rPos;
	}
	
	RequestResult res;
	RequestErr status;
	size_t requestLineLen;
	if (lineEndPos == nullptr)
	{
		requestLineLen = receivedBytes;
		status = RequestErr::BAD_REQUEST;
		res.version = HttpVersion::V1_0;
	}
	else
	{
		requestLineLen = lineEndPos - buffer;
		status = readRequestLine(buffer, requestLineLen, res);
	}
	
	char pathBuff[1024];
	const char* path = nullptr;
	
	switch (status)
	{
	case RequestErr::OK:
		{
			int unescapedLen = unescape(res.path, pathBuff, res.pathLen);
			if (unescapedLen == -1)
			{
				status = RequestErr::BAD_REQUEST;
				path = "/400.html";
			}
			else
			{						
				pathBuff[unescapedLen] = 0;
				path = pathBuff;
			}
		}
		break;
		
	case RequestErr::BAD_REQUEST:
		path = "/400.html";
		break;
		
	case RequestErr::FORBIDDEN:
		path = "/403.html";
		break;
		
	case RequestErr::NOT_FOUND:
		path = "/404.html";
		break;
		
	case RequestErr::INTERNAL:
		path = "/500.html";
		break;
		
	case RequestErr::NOT_IMPLEMENTED:
		path = "/501.html";
		break;
	}
	
	if (strcmp(path, "/") == 0)
	{
		path = "/index.html";
	}
	
	int file = open(path, O_RDONLY);
	if (file == -1)
	{
		status = RequestErr::NOT_FOUND;
		file = open("/404.html", O_RDONLY);
		
		if (file == -1)
		{
			Log::err("open(): %s, Failed to open 404.html", strerror(errno));
			
			if (close(connSock) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			return Err::Process;
		}
	}
		
	struct stat fileStat;
	if (fstat(file, &fileStat) == -1)
	{
		Log::err("fstat(): %s", strerror(errno));
		
		if (close(file) == -1)
		{
			Log::err("close(): %s", strerror(errno));
		}
		
		if (close(connSock) == -1)
		{
			Log::err("close(): %s", strerror(errno));
		}
		
		return Err::Process;
	}
	
	if (res.version >= HttpVersion::V1_0)
	{
		char headerBuff[1024];
		int headerLen = snprintf(headerBuff, sizeof(headerBuff), "HTTP/1.0 %3.3d %s\r\n", (int)status, getStatusStr(status));
		
		const char* mimeType = mimeFinder->findMimeType(dup(file), path);
		if (lseek(file, 0, SEEK_SET) == -1)
		{
			Log::err("lseek(): %s", strerror(errno));
			
			if (close(file) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			if (close(connSock) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			return Err::Process;
		}
		if (mimeType != nullptr)
		{
			headerLen += snprintf(headerBuff + headerLen, sizeof(headerBuff) - headerLen,
				"Content-Type: %s\r\n", mimeType);
		}
		
		headerLen += snprintf(headerBuff + headerLen, sizeof(headerBuff) - headerLen, "Content-Length: %ld\r\n\r\n", fileStat.st_size);
		
		if (send(connSock, headerBuff, headerLen, 0) == -1)
		{
			Log::err("send(): %s", strerror(errno));
			
			if (close(file) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			if (close(connSock) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			return Err::Process;
		}
	}
	
	size_t bytesSent;
	if(res.method == HttpMethod::GET)
	{
		if ((bytesSent = sendfile(connSock, file, nullptr, fileStat.st_size)) == -1)
		{
			Log::err("sendfile(): %s", strerror(errno));
			
			if (close(file) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			if (close(connSock) == -1)
			{
				Log::err("close(): %s", strerror(errno));
			}
			
			return Err::Process;
		}
	}
	
	if(close(file) == -1)
	{
		Log::err("close(): %s", strerror(errno));
	}
	
	logStatus(buffer, requestLineLen, connSock, bytesSent, (int)status);
	
	if (close(connSock) == -1)
	{
		Log::err("close(): %s", strerror(errno));
	}
	
	return Err::OK;
}
コード例 #2
0
ファイル: abyss_http.c プロジェクト: 4N7HR4X/kamailio
abyss_bool
RequestRead(TSession * const sessionP) {
    uint16_t httpErrorCode;  /* zero for no error */
    char * requestLine;

    readRequestLine(sessionP, &requestLine, &httpErrorCode);
    if (!httpErrorCode) {
        TMethod httpMethod;
        const char * host;
        const char * path;
        const char * query;
        unsigned short port;
        abyss_bool moreHeaders=false;

        parseRequestLine(requestLine, &httpMethod, &sessionP->version,
                         &host, &port, &path, &query,
                         &moreHeaders, &httpErrorCode);

        if (!httpErrorCode)
            initRequestInfo(&sessionP->request_info, sessionP->version,
                            strdup(requestLine),
                            httpMethod, host, port, path, query);

        while (moreHeaders && !httpErrorCode) {
            char * p;
            abyss_bool succeeded;
            succeeded = ConnReadHeader(sessionP->conn, &p);
            if (!succeeded)
                httpErrorCode = 408;  /* Request Timeout */
            else {
                if (!*p)
                    /* We have reached the empty line so all the request
                       was read.
                    */
                    moreHeaders = FALSE;
                else {
                    char * fieldName;
                    getFieldNameToken(&p, &fieldName, &httpErrorCode);
                    if (!httpErrorCode) {
                        char * fieldValue;

                        NextToken((const char **)&p);
                        
                        fieldValue = p;
                        
                        TableAdd(&sessionP->request_headers,
                                 fieldName, fieldValue);
                        
                        processHeader(fieldName, fieldValue, sessionP,
                                      &httpErrorCode);
                    }
                }
            }
        }
    }
    if (httpErrorCode)
        ResponseStatus(sessionP, httpErrorCode);
    else
        sessionP->validRequest = true;

    return !httpErrorCode;
}