public HttpResponse processRequest(HttpRequest request)
        {

            // vvv `chrome` (and possibly others) preflights any CORS requests
            if (HttpMethod.OPTIONS == request.Method)
            {
                return buildOptionsResponse(request);
            }
            // ^^^ `chrome` (and possibly others) preflights any CORS requests


            HttpResponse answer = ServicesRequestHandler.processPostRequest(_servicesRegistery, request);

            // vvv without echoing back the 'origin' for CORS requests, chrome (and possibly others) complains "Origin http://localhost:8081 is not allowed by Access-Control-Allow-Origin."
            {
                String origin = request.getHttpHeader("origin");
                if (null != origin)
                {
                    answer.putHeader("Access-Control-Allow-Origin", origin);
                }
            }
            // ^^^ without echoing back the 'origin' for CORS requests, chrome (and possibly others) complains "Origin http://localhost:8081 is not allowed by Access-Control-Allow-Origin."

            return answer;
        }
        private HttpResponse buildOptionsResponse(HttpRequest request)
        {
            HttpResponse answer = new HttpResponse(HttpStatus.NO_CONTENT_204);

            // vvv http://www.w3.org/TR/cors/#access-control-allow-methods-response-header
            answer.putHeader("Access-Control-Allow-Methods", "OPTIONS, POST");
            // ^^^ http://www.w3.org/TR/cors/#access-control-allow-methods-response-header


            String accessControlAllowOrigin = request.getHttpHeader("origin");
            if (null == accessControlAllowOrigin)
            {
                accessControlAllowOrigin = "*";
            }
            answer.putHeader("Access-Control-Allow-Origin", accessControlAllowOrigin);

            String accessControlRequestHeaders = request.getHttpHeader("access-control-request-headers");
            if (null != accessControlRequestHeaders)
            {
                answer.putHeader("Access-Control-Allow-Headers", accessControlRequestHeaders);
            }
            
            return answer;
        }
        private Authorization getAuthorizationRequestHeader(HttpRequest request)
        {

            Authorization answer = null;


            String authorization = request.getHttpHeader("Authorization");
            if (null == authorization)
            {
                log.error("null == authorization");
                throw HttpErrorHelper.unauthorized401FromOriginator(this);
            }

            answer = Authorization.buildFromString(authorization);

            if (!"auth-int".Equals(answer.qop))
            {
                log.errorFormat("!\"auth-int\".Equals(answer.qop); answer.qop = '{0}'", answer.qop);
                throw HttpErrorHelper.unauthorized401FromOriginator(this);
            }

            return answer;
        }
        public HttpResponse processRequest(HttpRequest request)
        {

            String requestUri = request.RequestUri;

            if (requestUri.EndsWith("/"))
            {
                requestUri = requestUri + "index.html";
            }

            { // some validation
                validateRequestUri(requestUri);
                validateMimeTypeForRequestUri(requestUri);
            }

			FileInfo absoluteFileInfo = toAbsoluteFileInfo(requestUri);


			String eTag = getETag(absoluteFileInfo);

			HttpResponse answer;

			String ifNoneMatch = request.getHttpHeader("if-none-match");
			if (null != ifNoneMatch && ifNoneMatch.Equals(eTag))
			{
				answer = new HttpResponse(HttpStatus.NOT_MODIFIED_304);
			}
			else {

				Entity body = readFile(absoluteFileInfo);
				answer = new HttpResponse(HttpStatus.OK_200, body);
				String contentType = MimeTypes.getMimeTypeForPath(requestUri);
				answer.setContentType(contentType);

			}

			if (null != _cacheControl)
			{
				answer.putHeader(_cacheControl.getName(), _cacheControl.getValue());
			}
				

			{
				answer.putHeader("Date", DateTime.UtcNow.ToString("R"));
			}

			{
				var lastModified = absoluteFileInfo.LastWriteTimeUtc;
				answer.putHeader("Last-Modified", lastModified.ToString("R"));
			}


			answer.putHeader("ETag", eTag);
			return answer;

        }