catch issue where the connection was closed before reply
This commit is contained in:
		
							
								
								
									
										252
									
								
								mod.ts
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								mod.ts
									
									
									
									
									
								
							@@ -102,145 +102,149 @@ export class HTTPServer {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async handleHttp(conn: Deno.Conn) {
 | 
					  private async handleHttp(conn: Deno.Conn) {
 | 
				
			||||||
    const httpConn = Deno.serveHttp(conn);
 | 
					    try {
 | 
				
			||||||
    for await (const requestEvent of httpConn) {
 | 
					      const httpConn = Deno.serveHttp(conn);
 | 
				
			||||||
      const filepath = decodeURIComponent(
 | 
					      for await (const requestEvent of httpConn) {
 | 
				
			||||||
        "/" + requestEvent.request.url.split("/").slice(3).join("/"),
 | 
					        const filepath = decodeURIComponent(
 | 
				
			||||||
      );
 | 
					          "/" + requestEvent.request.url.split("/").slice(3).join("/"),
 | 
				
			||||||
      const request = requestEvent.request;
 | 
					 | 
				
			||||||
      const url = request.url;
 | 
					 | 
				
			||||||
      const routeRequest = new RouteRequest(
 | 
					 | 
				
			||||||
        request,
 | 
					 | 
				
			||||||
        conn,
 | 
					 | 
				
			||||||
        filepath,
 | 
					 | 
				
			||||||
        url,
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      const routeReply: RouteReply = new RouteReply();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (filepath.startsWith("/_static") || filepath.endsWith(".ico")) {
 | 
					 | 
				
			||||||
        this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this.preprocessors.forEach((preProcessor) =>
 | 
					 | 
				
			||||||
        preProcessor(routeRequest, routeReply)
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      let resolveAction: (value: number[]) => void = () => {};
 | 
					 | 
				
			||||||
      let middlewarePromise;
 | 
					 | 
				
			||||||
      const perStart = performance.now();
 | 
					 | 
				
			||||||
      if (this.middlewareHandler) {
 | 
					 | 
				
			||||||
        middlewarePromise = (): Promise<number[]> => {
 | 
					 | 
				
			||||||
          return new Promise((resolve) => {
 | 
					 | 
				
			||||||
            resolveAction = resolve;
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        this.middlewareHandler(routeRequest, routeReply, middlewarePromise);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (this.staticServePath && filepath.startsWith(this.staticServePath)) {
 | 
					 | 
				
			||||||
        const fileDir = filepath.split("/").slice(2).join("/");
 | 
					 | 
				
			||||||
        const pathLoc = path.join(
 | 
					 | 
				
			||||||
          Deno.cwd(),
 | 
					 | 
				
			||||||
          this.staticLocalDir as string,
 | 
					 | 
				
			||||||
          fileDir,
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        let file;
 | 
					        const request = requestEvent.request;
 | 
				
			||||||
        try {
 | 
					        const url = request.url;
 | 
				
			||||||
          file = await Deno.open(pathLoc, { read: true });
 | 
					        const routeRequest = new RouteRequest(
 | 
				
			||||||
        } catch {
 | 
					          request,
 | 
				
			||||||
 | 
					          conn,
 | 
				
			||||||
 | 
					          filepath,
 | 
				
			||||||
 | 
					          url,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const routeReply: RouteReply = new RouteReply();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (filepath.startsWith("/_static") || filepath.endsWith(".ico")) {
 | 
				
			||||||
 | 
					          this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.preprocessors.forEach((preProcessor) =>
 | 
				
			||||||
 | 
					          preProcessor(routeRequest, routeReply)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let resolveAction: (value: number[]) => void = () => {};
 | 
				
			||||||
 | 
					        let middlewarePromise;
 | 
				
			||||||
 | 
					        const perStart = performance.now();
 | 
				
			||||||
 | 
					        if (this.middlewareHandler) {
 | 
				
			||||||
 | 
					          middlewarePromise = (): Promise<number[]> => {
 | 
				
			||||||
 | 
					            return new Promise((resolve) => {
 | 
				
			||||||
 | 
					              resolveAction = resolve;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          this.middlewareHandler(routeRequest, routeReply, middlewarePromise);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.staticServePath && filepath.startsWith(this.staticServePath)) {
 | 
				
			||||||
 | 
					          const fileDir = filepath.split("/").slice(2).join("/");
 | 
				
			||||||
 | 
					          const pathLoc = path.join(
 | 
				
			||||||
 | 
					            Deno.cwd(),
 | 
				
			||||||
 | 
					            this.staticLocalDir as string,
 | 
				
			||||||
 | 
					            fileDir,
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          let file;
 | 
				
			||||||
 | 
					          try {
 | 
				
			||||||
 | 
					            file = await Deno.open(pathLoc, { read: true });
 | 
				
			||||||
 | 
					          } catch {
 | 
				
			||||||
 | 
					            if (middlewarePromise) {
 | 
				
			||||||
 | 
					              const pt = performance.now() - perStart;
 | 
				
			||||||
 | 
					              const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
				
			||||||
 | 
					              resolveAction(hrArray);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const readableStream = file.readable;
 | 
				
			||||||
 | 
					          const response = new Response(readableStream);
 | 
				
			||||||
          if (middlewarePromise) {
 | 
					          if (middlewarePromise) {
 | 
				
			||||||
            const pt = performance.now() - perStart;
 | 
					            const pt = performance.now() - perStart;
 | 
				
			||||||
            const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
					            const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
				
			||||||
            resolveAction(hrArray);
 | 
					            resolveAction(hrArray);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
					          await requestEvent.respondWith(response);
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const routeName = `${requestEvent.request.method}@${filepath}`;
 | 
				
			||||||
 | 
					        let route = this.routes.get(routeName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (route) {
 | 
				
			||||||
 | 
					          let handler = await route.handler(
 | 
				
			||||||
 | 
					            routeRequest,
 | 
				
			||||||
 | 
					            routeReply,
 | 
				
			||||||
 | 
					          ) ?? routeReply.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (typeof (handler) == "object") {
 | 
				
			||||||
 | 
					            handler = JSON.stringify(handler, null, 2);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (middlewarePromise) {
 | 
				
			||||||
 | 
					            const pt = performance.now() - perStart;
 | 
				
			||||||
 | 
					            const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
				
			||||||
 | 
					            resolveAction(hrArray);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          await requestEvent.respondWith(
 | 
				
			||||||
 | 
					            new Response(handler as string, {
 | 
				
			||||||
 | 
					              status: routeReply.statusCode,
 | 
				
			||||||
 | 
					              headers: routeReply.headers,
 | 
				
			||||||
 | 
					              statusText: STATUS_TEXT[routeReply.statusCode],
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
          continue;
 | 
					          continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const readableStream = file.readable;
 | 
					        route = Array.from(this.routes.values()).find((route) =>
 | 
				
			||||||
        const response = new Response(readableStream);
 | 
					          routeWithParamsRouteMatcher(routeRequest, route)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (route) {
 | 
				
			||||||
 | 
					          const routeParamsMap: RouteParam[] = extractRouteParams(route.path);
 | 
				
			||||||
 | 
					          const routeSegments: string[] = filepath.split("/");
 | 
				
			||||||
 | 
					          routeRequest.pathParams = routeParamsMap.reduce(
 | 
				
			||||||
 | 
					            (accum: { [key: string]: string }, curr: RouteParam) => {
 | 
				
			||||||
 | 
					              return {
 | 
				
			||||||
 | 
					                ...accum,
 | 
				
			||||||
 | 
					                [curr.paramKey]: routeSegments[curr.idx].replace(
 | 
				
			||||||
 | 
					                  /(?!\/)\W\D.*/gm,
 | 
				
			||||||
 | 
					                  "",
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {},
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const handler = await route.handler(
 | 
				
			||||||
 | 
					            routeRequest,
 | 
				
			||||||
 | 
					            routeReply,
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          if (middlewarePromise) {
 | 
				
			||||||
 | 
					            const pt = performance.now() - perStart;
 | 
				
			||||||
 | 
					            const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
				
			||||||
 | 
					            resolveAction(hrArray);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          await requestEvent.respondWith(
 | 
				
			||||||
 | 
					            new Response(handler as string, {
 | 
				
			||||||
 | 
					              status: routeReply.statusCode,
 | 
				
			||||||
 | 
					              headers: routeReply.headers,
 | 
				
			||||||
 | 
					              statusText: STATUS_TEXT[routeReply.statusCode],
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (middlewarePromise) {
 | 
					        if (middlewarePromise) {
 | 
				
			||||||
          const pt = performance.now() - perStart;
 | 
					          const pt = performance.now() - perStart;
 | 
				
			||||||
          const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
					          const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
				
			||||||
          resolveAction(hrArray);
 | 
					          resolveAction(hrArray);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        await requestEvent.respondWith(response);
 | 
					        this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (_err) {
 | 
				
			||||||
      const routeName = `${requestEvent.request.method}@${filepath}`;
 | 
					      // Ignore http that where closed before reply was sent
 | 
				
			||||||
      let route = this.routes.get(routeName);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (route) {
 | 
					 | 
				
			||||||
        let handler = await route.handler(
 | 
					 | 
				
			||||||
          routeRequest,
 | 
					 | 
				
			||||||
          routeReply,
 | 
					 | 
				
			||||||
        ) ?? routeReply.body;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (typeof (handler) == "object") {
 | 
					 | 
				
			||||||
          handler = JSON.stringify(handler, null, 2);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (middlewarePromise) {
 | 
					 | 
				
			||||||
          const pt = performance.now() - perStart;
 | 
					 | 
				
			||||||
          const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
					 | 
				
			||||||
          resolveAction(hrArray);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        await requestEvent.respondWith(
 | 
					 | 
				
			||||||
          new Response(handler as string, {
 | 
					 | 
				
			||||||
            status: routeReply.statusCode,
 | 
					 | 
				
			||||||
            headers: routeReply.headers,
 | 
					 | 
				
			||||||
            statusText: STATUS_TEXT[routeReply.statusCode],
 | 
					 | 
				
			||||||
          }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      route = Array.from(this.routes.values()).find((route) =>
 | 
					 | 
				
			||||||
        routeWithParamsRouteMatcher(routeRequest, route)
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (route) {
 | 
					 | 
				
			||||||
        const routeParamsMap: RouteParam[] = extractRouteParams(route.path);
 | 
					 | 
				
			||||||
        const routeSegments: string[] = filepath.split("/");
 | 
					 | 
				
			||||||
        routeRequest.pathParams = routeParamsMap.reduce(
 | 
					 | 
				
			||||||
          (accum: { [key: string]: string }, curr: RouteParam) => {
 | 
					 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
              ...accum,
 | 
					 | 
				
			||||||
              [curr.paramKey]: routeSegments[curr.idx].replace(
 | 
					 | 
				
			||||||
                /(?!\/)\W\D.*/gm,
 | 
					 | 
				
			||||||
                "",
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          {},
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const handler = await route.handler(
 | 
					 | 
				
			||||||
          routeRequest,
 | 
					 | 
				
			||||||
          routeReply,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        if (middlewarePromise) {
 | 
					 | 
				
			||||||
          const pt = performance.now() - perStart;
 | 
					 | 
				
			||||||
          const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
					 | 
				
			||||||
          resolveAction(hrArray);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        await requestEvent.respondWith(
 | 
					 | 
				
			||||||
          new Response(handler as string, {
 | 
					 | 
				
			||||||
            status: routeReply.statusCode,
 | 
					 | 
				
			||||||
            headers: routeReply.headers,
 | 
					 | 
				
			||||||
            statusText: STATUS_TEXT[routeReply.statusCode],
 | 
					 | 
				
			||||||
          }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (middlewarePromise) {
 | 
					 | 
				
			||||||
        const pt = performance.now() - perStart;
 | 
					 | 
				
			||||||
        const hrArray: number[] = [0, Math.trunc(pt * 1000000)];
 | 
					 | 
				
			||||||
        resolveAction(hrArray);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      this.handleNotFound(routeRequest, routeReply, requestEvent);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user