Search in sources :

Example 1 with QValue

use of com.helger.http.QValue in project ph-web by phax.

the class UnifiedResponse method applyToResponse.

public final void applyToResponse(@Nonnull final HttpServletResponse aHttpResponse) throws IOException {
    ValueEnforcer.notNull(aHttpResponse, "HttpResponse");
    // Apply all collected headers
    for (final Map.Entry<String, ICommonsList<String>> aEntry : m_aResponseHeaderMap) {
        final String sHeaderName = aEntry.getKey();
        int nIndex = 0;
        for (final String sHeaderValue : aEntry.getValue()) {
            // Ensure single line values
            final String sUnifiedHeaderValue = m_bHttpHeaderValuesUnified ? HttpHeaderMap.getUnifiedValue(sHeaderValue, m_bHttpHeaderValuesQuoteIfNecessary) : sHeaderValue;
            if (nIndex == 0)
                aHttpResponse.setHeader(sHeaderName, sUnifiedHeaderValue);
            else
                aHttpResponse.addHeader(sHeaderName, sUnifiedHeaderValue);
            ++nIndex;
        }
    }
    final boolean bIsRedirect = isRedirectDefined();
    final boolean bHasStatusCode = isStatusCodeDefined();
    if (bIsRedirect) {
        if (bHasStatusCode)
            logWarn("Ignoring provided status code because a redirect is specified!");
        if (!m_bAllowContentOnRedirect) {
            if (m_aCacheControl != null)
                logInfo("Ignoring provided Cache-Control because a redirect is specified!");
            if (m_sContentDispositionFilename != null)
                logWarn("Ignoring provided Content-Dispostion filename because a redirect is specified!");
            if (m_aMimeType != null)
                logWarn("Ignoring provided MimeType because a redirect is specified!");
            if (m_aCharset != null)
                logWarn("Ignoring provided charset because a redirect is specified!");
            if (hasContent())
                logWarn("Ignoring provided content because a redirect is specified!");
        }
        // Note: After using this method, the response should be
        // considered to be committed and should not be written to.
        String sRealTargetURL;
        if (ServletSettings.isEncodeURLs()) {
            try {
                sRealTargetURL = aHttpResponse.encodeRedirectURL(m_sRedirectTargetUrl);
            } catch (final IllegalArgumentException ex) {
                // Happens e.g. if "http://server/../" is requested
                LOGGER.warn("Failed to encode redirect target URL '" + m_sRedirectTargetUrl + "': " + ex.getMessage());
                sRealTargetURL = m_sRedirectTargetUrl;
            }
        } else
            sRealTargetURL = m_sRedirectTargetUrl;
        if (LOGGER.isDebugEnabled())
            LOGGER.debug("Response is a redirect to '" + sRealTargetURL + "' using mode " + m_eRedirectMode);
        switch(m_eRedirectMode) {
            case DEFAULT:
                aHttpResponse.sendRedirect(sRealTargetURL);
                break;
            case POST_REDIRECT_GET:
                if (m_eHttpVersion.is10()) {
                    // For HTTP 1.0 send 302
                    aHttpResponse.setStatus(HttpServletResponse.SC_FOUND);
                } else {
                    // For HTTP 1.1 send 303
                    aHttpResponse.setStatus(HttpServletResponse.SC_SEE_OTHER);
                }
                // Set the location header
                aHttpResponse.addHeader(CHttpHeader.LOCATION, sRealTargetURL);
                break;
            default:
                throw new IllegalStateException("Unimplemented redirect mode " + m_eRedirectMode + "!");
        }
        if (!m_bAllowContentOnRedirect)
            return;
    }
    if (bHasStatusCode) {
        if (bIsRedirect)
            logWarn("Overriding provided redirect because a status code is specified!");
        if (!m_bAllowContentOnStatusCode) {
            if (m_aCacheControl != null)
                logInfo("Ignoring provided Cache-Control because a status code is specified!");
            if (m_sContentDispositionFilename != null)
                logWarn("Ignoring provided Content-Dispostion filename because a status code is specified!");
            if (m_aMimeType != null)
                logWarn("Ignoring provided MimeType because a status code is specified!");
            if (m_aCharset != null)
                logWarn("Ignoring provided charset because a status code is specified!");
            if (hasContent())
                logWarn("Ignoring provided content because a status code is specified!");
        }
        if (m_nStatusCode == HttpServletResponse.SC_UNAUTHORIZED && !m_aResponseHeaderMap.containsHeaders(CHttpHeader.WWW_AUTHENTICATE))
            logWarn("Status code UNAUTHORIZED (401) is returned, but no " + CHttpHeader.WWW_AUTHENTICATE + " HTTP response header is set!");
        // Content may be present so, sendError is not an option here!
        if (m_nStatusCode >= HttpServletResponse.SC_BAD_REQUEST && m_aContentArray == null) {
            // It's an error
            // Note: After using this method, the response should be considered
            // to be committed and should not be written to.
            aHttpResponse.sendError(m_nStatusCode);
        } else {
            // It's a status message "only"
            // Note: The container clears the buffer and sets the Location
            // header, preserving cookies and other headers.
            aHttpResponse.setStatus(m_nStatusCode);
        }
        if (!m_bAllowContentOnStatusCode)
            return;
        if (!hasContent()) {
            // continue - would produce some warnings
            return;
        }
    }
    // Verify only if is a response with content
    _verifyCachingIntegrity();
    if (m_aCacheControl != null) {
        final String sCacheControlValue = m_aCacheControl.getAsHTTPHeaderValue();
        if (StringHelper.hasText(sCacheControlValue))
            aHttpResponse.setHeader(CHttpHeader.CACHE_CONTROL, sCacheControlValue);
        else
            logWarn("An empty Cache-Control was provided!");
    }
    if (m_sContentDispositionFilename != null) {
        final StringBuilder aSB = new StringBuilder();
        if (m_aRequestBrowserInfo != null && m_aRequestBrowserInfo.getBrowserType() == EBrowserType.IE && m_aRequestBrowserInfo.getVersion().getMajor() <= 8) {
            // Special case for IE <= 8
            final Charset aCharsetToUse = m_aCharset != null ? m_aCharset : StandardCharsets.UTF_8;
            aSB.append(m_eContentDispositionType.getID()).append("; filename=").append(URLHelper.urlEncode(m_sContentDispositionFilename, aCharsetToUse));
        } else {
            // Filename needs to be surrounded with double quotes (single quotes
            // don't work).
            aSB.append(m_eContentDispositionType.getID()).append("; filename=\"").append(m_sContentDispositionFilename).append('"');
            // Check if we need an UTF-8 filename
            // http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http/6745788#6745788
            final String sRFC5987Filename = RFC5987Encoder.getRFC5987EncodedUTF8(m_sContentDispositionFilename);
            if (!sRFC5987Filename.equals(m_sContentDispositionFilename))
                aSB.append("; filename*=UTF-8''").append(sRFC5987Filename);
        }
        aHttpResponse.setHeader(CHttpHeader.CONTENT_DISPOSITION, aSB.toString());
        if (m_aMimeType == null) {
            logWarn("Content-Disposition is specified but no MimeType is set. Using the default download MimeType.");
            aHttpResponse.setContentType(CMimeType.APPLICATION_FORCE_DOWNLOAD.getAsString());
        }
    }
    // Mime type
    if (m_aMimeType != null) {
        final String sMimeType = m_aMimeType.getAsString();
        // Check with request accept mime types
        final QValue aQuality = m_aAcceptMimeTypeList.getQValueOfMimeType(m_aMimeType);
        if (aQuality.isMinimumQuality()) {
            final ICommonsOrderedMap<IMimeType, QValue> aBetterValues = m_aAcceptMimeTypeList.getAllQValuesGreaterThan(aQuality.getQuality());
            logError("MimeType '" + sMimeType + "' is not at all supported by the request. Allowed values are: " + _getAsStringMimeTypes(aBetterValues));
        } else if (aQuality.isLowValue()) {
            // only in the debug version
            if (GlobalDebug.isDebugMode()) {
                // Inform if the quality of the request is <= 50%!
                final ICommonsOrderedMap<IMimeType, QValue> aBetterValues = m_aAcceptMimeTypeList.getAllQValuesGreaterThan(aQuality.getQuality());
                if (!aBetterValues.isEmpty())
                    logWarn("MimeType '" + sMimeType + "' is not best supported by the request (" + aQuality + "). Better MimeTypes are: " + _getAsStringMimeTypes(aBetterValues));
            }
        }
        aHttpResponse.setContentType(sMimeType);
    } else {
        logWarn("No MimeType present");
    }
    // Charset
    if (m_aCharset != null) {
        final String sCharset = m_aCharset.name();
        if (m_aMimeType == null)
            logWarn("If no MimeType present, the client cannot get notified about the character encoding '" + sCharset + "'");
        // Check with request charset
        final QValue aQuality = m_aAcceptCharsetList.getQValueOfCharset(sCharset);
        if (aQuality.isMinimumQuality()) {
            final ICommonsOrderedMap<String, QValue> aBetterValues = m_aAcceptCharsetList.getAllQValuesGreaterThan(aQuality.getQuality());
            logError("Character encoding '" + sCharset + "' is not at all supported by the request. Allowed values are: " + _getAsStringText(aBetterValues));
        } else if (aQuality.isLowValue()) {
            // Inform if the quality of the request is <= 50%!
            final ICommonsOrderedMap<String, QValue> aBetterValues = m_aAcceptCharsetList.getAllQValuesGreaterThan(aQuality.getQuality());
            if (!aBetterValues.isEmpty())
                logWarn("Character encoding '" + sCharset + "' is not best supported by the request (" + aQuality + "). Better charsets are: " + _getAsStringText(aBetterValues));
        }
        aHttpResponse.setCharacterEncoding(sCharset);
    } else if (m_aMimeType == null) {
        logWarn("Also no character encoding present");
    } else
        switch(m_aMimeType.getContentType()) {
            case TEXT:
            case MULTIPART:
                logWarn("A character encoding for MimeType '" + m_aMimeType.getAsString() + "' is appreciated.");
                break;
            default:
                // Do we need character encoding here as well???
                break;
        }
    // Add all cookies
    if (m_aCookies != null)
        for (final Cookie aCookie : m_aCookies.values()) aHttpResponse.addCookie(aCookie);
    // Write the body to the response
    _applyContent(aHttpResponse, bHasStatusCode);
}
Also used : Cookie(javax.servlet.http.Cookie) ICommonsList(com.helger.commons.collection.impl.ICommonsList) QValue(com.helger.http.QValue) Charset(java.nio.charset.Charset) ICommonsOrderedMap(com.helger.commons.collection.impl.ICommonsOrderedMap) IMimeType(com.helger.commons.mime.IMimeType) HttpHeaderMap(com.helger.commons.http.HttpHeaderMap) Map(java.util.Map) ICommonsOrderedMap(com.helger.commons.collection.impl.ICommonsOrderedMap) ICommonsMap(com.helger.commons.collection.impl.ICommonsMap) CommonsLinkedHashMap(com.helger.commons.collection.impl.CommonsLinkedHashMap)

Aggregations

CommonsLinkedHashMap (com.helger.commons.collection.impl.CommonsLinkedHashMap)1 ICommonsList (com.helger.commons.collection.impl.ICommonsList)1 ICommonsMap (com.helger.commons.collection.impl.ICommonsMap)1 ICommonsOrderedMap (com.helger.commons.collection.impl.ICommonsOrderedMap)1 HttpHeaderMap (com.helger.commons.http.HttpHeaderMap)1 IMimeType (com.helger.commons.mime.IMimeType)1 QValue (com.helger.http.QValue)1 Charset (java.nio.charset.Charset)1 Map (java.util.Map)1 Cookie (javax.servlet.http.Cookie)1