Example #1
0
/**
**  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;
}