/** ** Wrapper for PercentDecode() and handles the return values from ** PercentDecode(). ** ** This really decodes the chars for UnicodeDecode(). If the char is ** a percent then we process stuff, otherwise we just increment the ** pointer and return. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** @param bare_byte value for a non-ASCII char or a decoded non-ASCII char ** ** @return integer ** ** @retval END_OF_BUFFER End of the buffer has been reached before decode. ** @retval NON_ASCII_CHAR End of buffer during decoding, return decoded char. ** @retval char return the valid decoded/undecoded char ** ** @see PercentDecode() ** @see GetByte() */ static int GetChar(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, int *bare_byte, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iNorm; if(!hi_util_in_bounds(start, end, *ptr)) return END_OF_BUFFER; iNorm = (int)(**ptr); if(**ptr == '%' && ServerConf->ascii.on) { /* ** We go into percent encoding. */ iNorm = PercentDecode(Session, start, end, ptr, norm_state, encodeType); /* ** If during the course of PercentDecode() we run into the end ** of the buffer, then we return early (WITHOUT INCREMENTING ptr) ** with a NON_ASCII_CHAR. */ if(iNorm == END_OF_BUFFER) return NON_ASCII_CHAR; *bare_byte = 0; } else { if(ServerConf->bare_byte.on && (u_char)iNorm > 0x7f) { *encodeType |= HTTP_ENCODE_TYPE__BARE_BYTE; if(hi_eo_generate_event(Session, ServerConf->bare_byte.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_BARE_BYTE, NULL, NULL); } /* ** Set the bare_byte flag */ *bare_byte = 0; } else { /* ** Set the bare_byte flag negative. */ *bare_byte = 1; } } /* ** Increment the buffer. */ (*ptr)++; return iNorm; }
// Decode a parameter value using the encoding defined in RFC 5987 // // charset "'" [ language ] "'" value-chars NS_IMETHODIMP nsMIMEHeaderParamImpl::DecodeRFC5987Param(const nsACString& aParamVal, nsACString& aLang, nsAString& aResult) { nsCAutoString charset; nsCAutoString language; nsCAutoString value; PRUint32 delimiters = 0; const char *encoded = PromiseFlatCString(aParamVal).get(); const char *c = encoded; while (*c) { char tc = *c++; if (tc == '\'') { // single quote delimiters++; } else if (tc >= 128) { // fail early, not ASCII NS_WARNING("non-US-ASCII character in RFC5987-encoded param"); return NS_ERROR_INVALID_ARG; } else { if (delimiters == 0) { // valid characters are checked later implicitly charset.Append(tc); } else if (delimiters == 1) { // no value checking for now language.Append(tc); } else if (delimiters == 2) { if (IsRFC5987AttrChar(tc)) { value.Append(tc); } else if (tc == '%') { if (!IsHexDigit(c[0]) || !IsHexDigit(c[1])) { // we expect two more characters NS_WARNING("broken %-escape in RFC5987-encoded param"); return NS_ERROR_INVALID_ARG; } value.Append(tc); // we consume two more value.Append(*c++); value.Append(*c++); } else { // character not allowed here NS_WARNING("invalid character in RFC5987-encoded param"); return NS_ERROR_INVALID_ARG; } } } } if (delimiters != 2) { NS_WARNING("missing delimiters in RFC5987-encoded param"); return NS_ERROR_INVALID_ARG; } // abort early for unsupported encodings if (!charset.LowerCaseEqualsLiteral("utf-8")) { NS_WARNING("unsupported charset in RFC5987-encoded param"); return NS_ERROR_INVALID_ARG; } // percent-decode if (!PercentDecode(value)) { return NS_ERROR_OUT_OF_MEMORY; } // return the encoding aLang.Assign(language); // finally convert octet sequence to UTF-8 and be done nsresult rv = NS_OK; nsCOMPtr<nsIUTF8ConverterService> cvtUTF8 = do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString utf8; rv = cvtUTF8->ConvertStringToUTF8(value, charset.get(), true, false, 1, utf8); NS_ENSURE_SUCCESS(rv, rv); CopyUTF8toUTF16(utf8, aResult); return NS_OK; }