ContentTypeUtilities.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.transport.http;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import javax.xml.soap.SOAPException;
- import org.openspcoop2.utils.Utilities;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.mime.MultipartUtils;
- import org.openspcoop2.utils.regexp.RegExpNotFoundException;
- import org.openspcoop2.utils.regexp.RegularExpressionEngine;
- import org.slf4j.Logger;
- //import javax.mail.internet.ContentType;
- //import javax.mail.internet.ParameterList;
- import com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType;
- import com.sun.xml.messaging.saaj.packaging.mime.internet.ParameterList;
- /**
- * ContentTypeUtilities
- *
- * @author Andrea Poli (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class ContentTypeUtilities {
-
-
-
- // Utilities generiche
-
- public static void validateContentType(String ct) throws UtilsException{
- try {
- if(ct!=null && !"".equals(ct)) {
-
- (new javax.mail.internet.ContentType(ct)).getBaseType(); // uso javax.mail per validare, restituisce un errore migliore
-
- if(ContentTypeUtilities.isMultipart(ct)){
- String internal = ContentTypeUtilities.getInternalMultipartContentType(ct);
- if(internal!=null){
- ContentTypeUtilities.isMtom(internal);
- }
- }
- }
- }catch(Throwable e) {
- String msgError = e.getMessage();
- if(msgError==null || "".equals(msgError) || "null".equals(msgError)) {
- msgError = Utilities.getInnerNotEmptyMessageException(e).getMessage();
- }
- if(msgError==null || "".equals(msgError) || "null".equals(msgError)) {
- msgError = "Parsing failed";
- }
- throw new UtilsException(msgError,e);
- }
- }
-
- public static String buildContentType(String baseType,Map<String, String> parameters) throws UtilsException{
- try{
- ContentType cType = new ContentType(baseType);
- if(parameters!=null && parameters.size()>0){
- Iterator<String> itP = parameters.keySet().iterator();
- while (itP.hasNext()) {
- String parameterName = (String) itP.next();
- String parameterValue = parameters.get(parameterName);
- if(cType.getParameterList()==null){
- cType.setParameterList(new ParameterList());
- }
- cType.getParameterList().remove(parameterName);
- cType.getParameterList().set(parameterName, parameterValue);
- }
-
- }
-
- /*
- * //import javax.mail.internet.ContentType;
- //import javax.mail.internet.ParameterList;
- import com.sun.xml.messaging.saaj.packaging.mime.internet.ContentType;
- import com.sun.xml.messaging.saaj.packaging.mime.internet.ParameterList;
-
- Utilizzo la versione saaj poiche il toString di javax.mail.internet.ContentType in presenza di un valore con ':' non funziona correttamente e genera valori action*0 e action*1
- *
- * */
-
- String ct = cType.toString(); // il toString in presenza di action con valore http://... non funziona correttamente e genera valori action*0 e action*1
-
- // Reimplementare il toString non basta poiche' i ':' fanno schiantare un successivo parser del javax.mail.internet.ContentType
- // StringBuilder ctBufferParam = new StringBuilder();
- // ParameterList pList = cType.getParameterList();
- // if(pList!=null && pList.size()>0) {
- // java.util.Enumeration<String> en = pList.getNames();
- // while (en.hasMoreElements()) {
- // String name = (String) en.nextElement();
- // ctBufferParam.append("; ");
- // ctBufferParam.append(name).append("=").append(pList.get(name));
- // }
- // }
- // String ct = cType.getBaseType();
- // if(ctBufferParam.length()>0) {
- // ct = ct + ctBufferParam.toString();
- // }
- ct = normalizeToRfc7230(ct);
- ct = ct.trim();
- return ct;
- }catch(Exception e){
- throw new RuntimeException("Error during buildContentType: "+e.getMessage(), e);
- }
- }
-
- public static String normalizeToRfc7230(String ct) {
- // Line folding of headers has been deprecated in the latest HTTP RFC:
- // http://tools.ietf.org/html/rfc7230#section-3.2.4
- while (ct.contains("\r\n")) {
- ct = ct.replace("\r\n", " ");
- }
- while (ct.contains("\r")) {
- ct = ct.replace("\r", " ");
- }
- while (ct.contains("\n")) {
- ct = ct.replace("\n", " ");
- }
- while (ct.contains("\t")) {
- ct = ct.replace("\t", " ");
- }
- return ct.trim();
- }
-
- public static String readBaseTypeFromContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- return contentType.getBaseType();
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
- public static String readPrimaryTypeFromContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- return contentType.getPrimaryType();
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
- public static String readSubTypeFromContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- return contentType.getSubType();
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public static String readCharsetFromContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String charsetParam = contentType.getParameter(HttpConstants.CONTENT_TYPE_PARAMETER_CHARSET);
- if (charsetParam != null) {
- return charsetParam.trim();
- }
- return null;
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
-
-
- // match
-
- public static boolean isMatch(Logger logNullable, String contentTypeParam, String contentTypeAtteso) throws UtilsException {
- List<String> l = new ArrayList<>();
- l.add(contentTypeAtteso);
- return isMatch(logNullable, contentTypeParam, l);
- }
- public static boolean isMatch(Logger logNullable, String contentTypeParam, List<String> contentTypeAttesi) throws UtilsException {
-
- if(contentTypeAttesi==null || contentTypeAttesi.isEmpty()) {
- return true;
- }
-
- String baseTypeHttp = contentTypeParam!=null ? ContentTypeUtilities.readBaseTypeFromContentType(contentTypeParam) : null;
-
- boolean found = false;
- for (String checkContentType : contentTypeAttesi) {
- if("empty".equals(checkContentType)){
- if(baseTypeHttp==null || "".equals(baseTypeHttp)) {
- found = true;
- break;
- }
- }
- else {
- if(baseTypeHttp==null) {
- continue;
- }
- if(checkContentType==null || "".equals(checkContentType) ||
- !checkContentType.contains("/") ||
- checkContentType.startsWith("/") ||
- checkContentType.endsWith("/")) {
- throw new UtilsException("Configurazione errata, content type indicato ("+checkContentType+") possiede un formato non corretto (atteso: type/subtype)");
- }
- String [] ctVerifica = checkContentType.split("/");
- String contentTypeEscaped = null;
- if(ctVerifica!=null && ctVerifica.length==2) {
- StringBuilder bf = new StringBuilder();
- String part1 = ctVerifica[0].trim();
- if("*".equals(part1)) {
- bf.append("(.+)");
- }
- else {
- // escape special char
- part1 = part1.replace("+", "\\+");
- bf.append(part1);
- }
- bf.append("/");
- String part2 = ctVerifica[1].trim();
- if("*".equals(part2)) {
- bf.append("(.+)");
- }
- else if(part2.startsWith("*")) {
- bf.append("(.+)");
- String sub = part2.substring(1);
- // escape special char
- sub = sub.replace("+", "\\+");
- bf.append(sub);
- }
- else {
- // escape special char
- part2 = part2.replace("+", "\\+");
- bf.append(part2);
- }
- contentTypeEscaped = bf.toString();
- }
- boolean isMatchEscaped = false; // gestisce le espressioni type/* e */*+xml
- boolean isMatchRegExp = false; // gestisce le espressioni regexpType/regexpSubType
- if(contentTypeEscaped!=null) {
- try {
- isMatchEscaped = RegularExpressionEngine.isMatch(baseTypeHttp, contentTypeEscaped);
- }catch(RegExpNotFoundException notFound) {
- // ignore
- }catch(Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
- if(!isMatchEscaped) {
- try {
- isMatchRegExp = RegularExpressionEngine.isMatch(baseTypeHttp, checkContentType);
- }catch(RegExpNotFoundException notFound) {
- // ignore
- }catch(Exception e) {
- if(contentTypeEscaped==null) {
- throw new UtilsException(e.getMessage(),e);
- }
- else {
- // ignore
- // per evitare errori tipo:
- //org.openspcoop2.utils.UtilsException: Validazione del pattern indicato [*/*son] fallita: Dangling meta character '*' near index 0
- // */*son
- // ^
- if(logNullable!=null) {
- logNullable.debug("isMatch failed: "+e.getMessage(),e);
- }
- }
- }
- }
- if(isMatchEscaped || isMatchRegExp) {
- found = true;
- break;
- }
- }
-
- }
- return found;
- }
-
-
-
-
- // Utilities Multipart
-
- public static boolean isMultipartType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String baseType = contentType.getBaseType();
- if(baseType!=null) {
- baseType = baseType.toLowerCase();
- }
- if(baseType!=null && baseType.startsWith(HttpConstants.CONTENT_TYPE_MULTIPART_TYPE+"/")){
- return true;
- }
- return false;
-
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- @Deprecated
- public static boolean isMultipart(String cType) throws UtilsException {
- return isMultipartRelated(cType);
- }
- public static boolean isMultipartRelated(String cType) throws UtilsException {
- return _isMultipart(cType, HttpConstants.CONTENT_TYPE_MULTIPART_RELATED);
- }
- public static boolean isMultipartMixed(String cType) throws UtilsException {
- return _isMultipart(cType, HttpConstants.CONTENT_TYPE_MULTIPART_MIXED);
- }
- public static boolean isMultipartAlternative(String cType) throws UtilsException {
- return _isMultipart(cType, HttpConstants.CONTENT_TYPE_MULTIPART_ALTERNATIVE);
- }
- public static boolean isMultipartFormData(String cType) throws UtilsException {
- return _isMultipart(cType, HttpConstants.CONTENT_TYPE_MULTIPART_FORM_DATA);
- }
- private static boolean _isMultipart(String cType, String expected) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String baseType = contentType.getBaseType();
- if(baseType!=null) {
- baseType = baseType.toLowerCase();
- }
- if(baseType!=null && baseType.equals(expected)){
- return true;
- }
- return false;
-
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public static boolean isMultipartContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String baseType = contentType.getBaseType();
- if(baseType!=null) {
- baseType = baseType.toLowerCase();
- }
- if(baseType!=null && baseType.startsWith( (HttpConstants.CONTENT_TYPE_MULTIPART_TYPE+"/")) ){
- return true;
- }
- return false;
-
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public static String getInternalMultipartContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String baseType = contentType.getBaseType();
- if(baseType!=null) {
- baseType = baseType.toLowerCase();
- }
- String internalContentType = null;
- boolean mtom = false;
- if(baseType == null) {
- internalContentType = null;
- }
- else if(baseType.equals(HttpConstants.CONTENT_TYPE_MULTIPART_RELATED)){
- String typeParam = contentType.getParameter(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE);
- if (typeParam != null) {
- internalContentType = typeParam.toLowerCase();
- if(HttpConstants.CONTENT_TYPE_APPLICATION_XOP_XML.equals(internalContentType)){
- mtom = true;
- }
- }
- }
- else {
- internalContentType = baseType;
- }
-
- if(mtom) {
- internalContentType = readInternalMultipartMtomContentType(contentType);
- }
-
- return internalContentType;
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- @Deprecated
- public static String buildMultipartContentType(byte [] message, String type) throws UtilsException{
- return buildMultipartRelatedContentType(message, type);
- }
- public static String buildMultipartRelatedContentType(byte [] message, String type) throws UtilsException{
- return buildMultipartContentType(HttpConstants.CONTENT_TYPE_MULTIPART_RELATED_SUBTYPE, message, type);
- }
- public static String buildMultipartContentType(String subtype, byte [] message, String type) throws UtilsException{
- if(MultipartUtils.messageWithAttachment(message)){
- String IDfirst = MultipartUtils.firstContentID(message);
- return buildMultipartContentType(subtype, message, type, IDfirst);
- }
- throw new UtilsException("Messaggio non contiene una struttura mime");
- }
- @Deprecated
- public static String buildMultipartContentType(byte [] message, String type, String ID) throws UtilsException{
- return buildMultipartRelatedContentType(message, type, ID);
- }
- public static String buildMultipartRelatedContentType(byte [] message, String type, String ID) throws UtilsException{
- return buildMultipartContentType(HttpConstants.CONTENT_TYPE_MULTIPART_RELATED_SUBTYPE, message, type, ID);
- }
- public static String buildMultipartContentType(String subtype, byte [] message, String type, String ID) throws UtilsException{
- if(MultipartUtils.messageWithAttachment(message)){
-
- String boundary = MultipartUtils.findBoundary(message);
- if(boundary==null){
- throw new UtilsException("Errore avvenuto durante la lettura del boundary associato al multipart message.");
- }
- StringBuilder bf = new StringBuilder();
- bf.append(HttpConstants.CONTENT_TYPE_MULTIPART_TYPE+"/"+subtype);
- if(type!=null){
- bf.append("; ").append(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE).append("=\"").append(type).append("\"");
- }
- if(ID!=null){
- bf.append("; ").append(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_START).append("=\"").append(ID).append("\"");
- }
- bf.append("; ").append(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_BOUNDARY).append("=\"").append(boundary.substring(2,boundary.length())).append("\"");
-
- return bf.toString();
- }
- throw new UtilsException("Messaggio non contiene una struttura mime");
- }
-
-
-
-
- // Utilities MTOM
-
- public static boolean isMtom(String cType) throws UtilsException{
- try{
- ContentType contentType = new ContentType(cType);
- String baseType = contentType.getBaseType();
- if(baseType!=null) {
- baseType = baseType.toLowerCase();
- }
- boolean mtom = false;
- if(baseType!=null && baseType.equals(HttpConstants.CONTENT_TYPE_MULTIPART_RELATED)){
- String typeParam = contentType.getParameter(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE);
- if (typeParam == null) {
- throw new SOAPException("Missing '"+HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE+"' parameter in "+HttpConstants.CONTENT_TYPE_MULTIPART_RELATED);
- } else {
- String soapContentType = typeParam.toLowerCase();
- if(HttpConstants.CONTENT_TYPE_APPLICATION_XOP_XML.equals(soapContentType)){
- mtom = true;
- }
- }
- }
- return mtom;
-
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public static String readInternalMultipartMtomContentType(String contentType) throws UtilsException{
- try{
- return readInternalMultipartMtomContentType(new ContentType(contentType));
- }
- catch(UtilsException e){
- throw e;
- }
- catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- public static String readInternalMultipartMtomContentType(ContentType contentType) throws UtilsException{
- try{
- if(contentType==null){
- throw new UtilsException("ContentType non fornito");
- }
-
- // baseType
- if(contentType.getBaseType()==null){
- throw new UtilsException("ContentType.baseType non definito");
- }
- if(HttpConstants.CONTENT_TYPE_MULTIPART_RELATED.equals(contentType.getBaseType().toLowerCase())==false){
- throw new UtilsException("ContentType.baseType ["+contentType.getBaseType()+
- "] differente da quello atteso per un messaggio MTOM/XOP ["+HttpConstants.CONTENT_TYPE_MULTIPART_RELATED+"]");
- }
- if(contentType.getParameterList()==null || contentType.getParameterList().size()<=0){
- throw new UtilsException("ContentType non conforme a quanto definito nella specifica MTOM/XOP (non sono presenti parametri)");
- }
-
- // type
- String type = contentType.getParameter(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE);
- if(type==null){
- throw new UtilsException("ContentType non conforme a quanto definito nella specifica MTOM/XOP (Parametro '"+
- HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE+"' non presente)");
- }
- if(HttpConstants.CONTENT_TYPE_APPLICATION_XOP_XML.equals(type.toLowerCase())==false){
- throw new UtilsException("ContentType.parameters."+HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_TYPE+" ["+type+
- "] differente da quello atteso per un messaggio MTOM/XOP ["+HttpConstants.CONTENT_TYPE_APPLICATION_XOP_XML+"]");
- }
-
- // startInfo
- String startInfo = contentType.getParameter(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_START_INFO);
- if(startInfo==null){
- throw new UtilsException("ContentType non conforme a quanto definito nella specifica MTOM/XOP (Parametro '"+
- HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_START_INFO+"' non presente)");
- }
- // startInfo puo' contenere il ';'
- return readBaseTypeFromContentType(startInfo);
-
- }
- catch(UtilsException e){
- throw e;
- }
- catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public static String readMultipartBoundaryFromContentType(String cType) throws UtilsException {
- try{
- ContentType contentType = new ContentType(cType);
- String boundaryParam = contentType.getParameter(HttpConstants.CONTENT_TYPE_MULTIPART_PARAMETER_BOUNDARY);
- if (boundaryParam != null) {
- return boundaryParam.trim();
- }
- return null;
- } catch (Exception e) {
- throw new UtilsException(e.getMessage(),e);
- }
- }
- }