mirror of
				https://git.macaw.me/skunky/uselesshttp.d.git
				synced 2025-11-03 10:45:11 +03:00 
			
		
		
		
	Переход на edge-triggered; устранение жора CPU
This commit is contained in:
		
							parent
							
								
									ca1662c403
								
							
						
					
					
						commit
						06f9e483c3
					
				
					 2 changed files with 51 additions and 33 deletions
				
			
		| 
						 | 
					@ -27,6 +27,15 @@ struct Server {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private shared int epfd, sock;
 | 
					    private shared int epfd, sock;
 | 
				
			||||||
    void start(MD...)() { // TODO: реализовать "слушальщика" хрюникс сокетов (AF_UNIX)
 | 
					    void start(MD...)() { // TODO: реализовать "слушальщика" хрюникс сокетов (AF_UNIX)
 | 
				
			||||||
 | 
					        // import core.stdc.signal;
 | 
				
			||||||
 | 
					        // extern(C) void z (int s) nothrow @nogc @system {
 | 
				
			||||||
 | 
					        //     signal(s, SIG_IGN);
 | 
				
			||||||
 | 
					        //     this.epfd.close();
 | 
				
			||||||
 | 
					        //     this.sock.close();
 | 
				
			||||||
 | 
					        //     raise(0);
 | 
				
			||||||
 | 
					        // }
 | 
				
			||||||
 | 
					        // signal(SIGINT, &z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool ipv6;
 | 
					        bool ipv6;
 | 
				
			||||||
        for (short i; i < address.length; ++i)
 | 
					        for (short i; i < address.length; ++i)
 | 
				
			||||||
            if (address[i] == ':') {ipv6=true;break;}
 | 
					            if (address[i] == ':') {ipv6=true;break;}
 | 
				
			||||||
| 
						 | 
					@ -47,15 +56,22 @@ struct Server {
 | 
				
			||||||
            err(bind(sock, cast(sockaddr*)&sockt, sockt.sizeof), "bind");
 | 
					            err(bind(sock, cast(sockaddr*)&sockt, sockt.sizeof), "bind");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int hz;
 | 
				
			||||||
        setsockopt(sock,
 | 
					        setsockopt(sock,
 | 
				
			||||||
            IPPROTO_TCP, TCP_NODELAY | SO_REUSEADDR | SO_REUSEPORT,
 | 
					            IPPROTO_TCP, SO_REUSEADDR,
 | 
				
			||||||
            cast(void*)(new int), int.sizeof);
 | 
					            cast(void*)hz, int.sizeof);
 | 
				
			||||||
 | 
					        setsockopt(sock,
 | 
				
			||||||
 | 
					            IPPROTO_TCP, TCP_NODELAY,
 | 
				
			||||||
 | 
					            cast(void*)hz, int.sizeof);
 | 
				
			||||||
 | 
					        // setsockopt(sock,
 | 
				
			||||||
 | 
					        //     IPPROTO_TCP, SO_REUSEPORT,
 | 
				
			||||||
 | 
					        //     cast(void*)hz, int.sizeof);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        err(listen(sock, 512), "listen");
 | 
					        err(listen(sock, 512), "listen");
 | 
				
			||||||
        serve!MD;
 | 
					        serve!MD;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void stop() {
 | 
					    void stop() @nogc {
 | 
				
			||||||
        epfd.close();
 | 
					        epfd.close();
 | 
				
			||||||
        sock.close();
 | 
					        sock.close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -66,7 +82,7 @@ struct Server {
 | 
				
			||||||
        epoll_event[MAX_EVENTS] evts;
 | 
					        epoll_event[MAX_EVENTS] evts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ev.data.fd = sock;
 | 
					        ev.data.fd = sock;
 | 
				
			||||||
        ev.events = EPOLLIN | EPOLLEXCLUSIVE;
 | 
					        ev.events = EPOLLIN;
 | 
				
			||||||
        epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
 | 
					        epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (;;) {
 | 
					        for (;;) {
 | 
				
			||||||
| 
						 | 
					@ -77,23 +93,35 @@ struct Server {
 | 
				
			||||||
                    // sockaddr_in addr;
 | 
					                    // sockaddr_in addr;
 | 
				
			||||||
                    // socklen_t al = sockaddr_in.sizeof;
 | 
					                    // socklen_t al = sockaddr_in.sizeof;
 | 
				
			||||||
                    // ev.data.fd = accept4(sock, cast(sockaddr*)&addr, &al, SOCK_NONBLOCK);
 | 
					                    // ev.data.fd = accept4(sock, cast(sockaddr*)&addr, &al, SOCK_NONBLOCK);
 | 
				
			||||||
 | 
					                    ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
 | 
				
			||||||
                    ev.data.fd = accept4(sock, null, null, SOCK_NONBLOCK);
 | 
					                    ev.data.fd = accept4(sock, null, null, SOCK_NONBLOCK);
 | 
				
			||||||
                    epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
 | 
					                    epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
 | 
				
			||||||
                    // ip = cast(string)inet_ntoa(addr.sin_addr);
 | 
					                    // ip = cast(string)inet_ntoa(addr.sin_addr);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // if (ev.data.fd == -1) { 
 | 
					                if (evts[i].events & EPOLLRDHUP) {
 | 
				
			||||||
 | 
					                    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, null);
 | 
				
			||||||
 | 
					                    close(fd);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                rd:
 | 
					                rd:
 | 
				
			||||||
                ubyte[128] buf;
 | 
					                ubyte[256] buf;
 | 
				
			||||||
                for (;;) { // обработчик запросов
 | 
					                for (;;) { // обработчик запросов
 | 
				
			||||||
                    auto rd = recv(fd, cast(void*)buf, buf.sizeof, 0);
 | 
					                    auto rd = recv(fd, cast(void*)buf, buf.sizeof, 0);
 | 
				
			||||||
                    if (rd < 1) break;
 | 
					                    if (rd < 1) break;
 | 
				
			||||||
                    auto rqst = parseReq(buf);
 | 
					                    auto rqst = parseReq(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (parseAndValidateURL(rqst.path, &rqst)) {
 | 
				
			||||||
 | 
					                        static auto resp = "HTTP/1.1 400 Bad Request\r\nContent-length: 15\r\n\r\n400 Bad Request";
 | 
				
			||||||
 | 
					                        write(fd, cast(void*)resp, resp.length);
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    static foreach (mm; __traits(allMembers, T)) {
 | 
					                    static foreach (mm; __traits(allMembers, T)) {
 | 
				
			||||||
                        static if (__traits(isStaticFunction,  __traits(getMember, T, mm))) {
 | 
					                        static if (__traits(isStaticFunction,  __traits(getMember, T, mm))) {
 | 
				
			||||||
                            foreach(attr; __traits(getAttributes,  __traits(getMember, T, mm))) {
 | 
					                            foreach(attr; __traits(getAttributes,  __traits(getMember, T, mm))) {
 | 
				
			||||||
                                static if (is(typeof(attr) == Location)) {
 | 
					                                static if (is(typeof(attr) == Location)) {
 | 
				
			||||||
                                    parseAndValidateURL(rqst.path, &rqst);
 | 
					 | 
				
			||||||
                                    if (rqst.path == attr.path) {
 | 
					                                    if (rqst.path == attr.path) {
 | 
				
			||||||
                                        Response rsp;
 | 
					                                        Response rsp;
 | 
				
			||||||
                                        __traits(getMember, T, mm)(&rsp, &rqst);
 | 
					                                        __traits(getMember, T, mm)(&rsp, &rqst);
 | 
				
			||||||
| 
						 | 
					@ -123,7 +151,8 @@ struct Server {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Request parseReq(ubyte[] body) { // TODO: реализовать парсинг заголовков, оформленных хер пойми как
 | 
					    // TODO: реализовать парсинг заголовков, оформленных хер пойми как
 | 
				
			||||||
 | 
					    Request parseReq(ubyte[] body) {
 | 
				
			||||||
        int prev;
 | 
					        int prev;
 | 
				
			||||||
        short[] xxx;
 | 
					        short[] xxx;
 | 
				
			||||||
        Request req;
 | 
					        Request req;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,27 +30,10 @@ string getStatus(short status) {
 | 
				
			||||||
    return "WTF";
 | 
					    return "WTF";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FIXME: memory leak
 | 
					short parseAndValidateURL(char[] url, Request* rqst) {
 | 
				
			||||||
void append(char[]* src, char symb) @nogc {
 | 
					    if (url.length > 2048) return 1; // too long url
 | 
				
			||||||
    import core.memory: pureMalloc, pureFree;
 | 
					 | 
				
			||||||
    auto arr = 
 | 
					 | 
				
			||||||
        cast (char[])
 | 
					 | 
				
			||||||
        pureMalloc(src.length + 1)
 | 
					 | 
				
			||||||
        [0..src.length + 1];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    arr[$-1..$] = symb;
 | 
					 | 
				
			||||||
    arr[0..$-1] = *src;
 | 
					 | 
				
			||||||
    *src = arr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    arr = null;
 | 
					 | 
				
			||||||
    pureFree(arr.ptr);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void parseAndValidateURL(char[] url, Request* rqst) {
 | 
					 | 
				
			||||||
    if (url.length > 2048) throw new Exception("Too long URL");
 | 
					 | 
				
			||||||
    rqst.path = null;
 | 
					    rqst.path = null;
 | 
				
			||||||
    bool notArgumentPart;
 | 
					    bool notArgumentPart;
 | 
				
			||||||
    scope (exit) append(&rqst.args, '&');
 | 
					 | 
				
			||||||
    for (short i; i < url.length; ++i) {
 | 
					    for (short i; i < url.length; ++i) {
 | 
				
			||||||
        switch (url[i]) {
 | 
					        switch (url[i]) {
 | 
				
			||||||
            case '?':
 | 
					            case '?':
 | 
				
			||||||
| 
						 | 
					@ -58,22 +41,24 @@ void parseAndValidateURL(char[] url, Request* rqst) {
 | 
				
			||||||
                notArgumentPart = true;
 | 
					                notArgumentPart = true;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case '/':
 | 
					            case '/':
 | 
				
			||||||
                if (url.length > i+1 && url[i+1] != '/') append(&rqst.path, '/');
 | 
					                if (url.length > i+1 && url[i+1] != '/') rqst.path ~= '/';
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case '=', '&':
 | 
					            case '=', '&':
 | 
				
			||||||
                if (notArgumentPart && url[i-1] != url[i]) append(&rqst.args, url[i]);
 | 
					                if (notArgumentPart && url[i-1] != url[i]) rqst.args ~= url[i];
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case 'A': .. case 'Z':
 | 
					            case 'A': .. case 'Z':
 | 
				
			||||||
            case 'a': .. case 'z':
 | 
					            case 'a': .. case 'z':
 | 
				
			||||||
            case '0': .. case '9':
 | 
					            case '0': .. case '9':
 | 
				
			||||||
            case '-', '_', '.', '~', '!', '$', '\'', '(', ')', '*', '+', ',', ';', '@', '[', ']', '|', '%':
 | 
					            case '-', '_', '.', '~', '!', '$', '\'', '(', ')', '*', '+', ',', ';', '@', '[', ']', '|', '%':
 | 
				
			||||||
                if (notArgumentPart) append(&rqst.args, url[i]);
 | 
					                if (notArgumentPart) rqst.args ~= url[i];
 | 
				
			||||||
                else append(&rqst.path, url[i]);
 | 
					                else rqst.path ~= url[i];
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            default: throw new Exception("Malformed URL");
 | 
					            default: return 1; // malformed url
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    rqst.args ~= '&';
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Request {
 | 
					struct Request {
 | 
				
			||||||
| 
						 | 
					@ -173,5 +158,9 @@ private static enum Statuses: short { // спизженно с https://github.co
 | 
				
			||||||
    @("Service Unavailable") service_unavailable = 503,
 | 
					    @("Service Unavailable") service_unavailable = 503,
 | 
				
			||||||
    @("Gateway Timeout") gateway_timeout = 504,
 | 
					    @("Gateway Timeout") gateway_timeout = 504,
 | 
				
			||||||
    @("HTTP Version Not Supported") http_version_not_supported = 505,
 | 
					    @("HTTP Version Not Supported") http_version_not_supported = 505,
 | 
				
			||||||
    @("Variant Also Negotiates") variant_also_negotiates = 506
 | 
					    @("Variant Also Negotiates") variant_also_negotiates = 506,
 | 
				
			||||||
 | 
					    @("Insufficient Storage") insufficient_storage = 507, // (WebDAV)
 | 
				
			||||||
 | 
					    @("Loop Detected") loop_detected = 508, // (WebDAV)
 | 
				
			||||||
 | 
					    @("Not Extended") not_extended = 510,
 | 
				
			||||||
 | 
					    @("Network Authentication Required") network_authentication_required = 511
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue