Package com.ericsson.ssa.sip

Source Code of com.ericsson.ssa.sip.SipServletRequestImpl

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip;

import com.ericsson.ssa.config.LayerHandler;
import com.ericsson.ssa.config.SipRequestDispatcher;
import com.ericsson.ssa.container.sim.ArInfo;
import static com.ericsson.ssa.sip.Header.P_ASSERTED_ID;
import static com.ericsson.ssa.sip.Header.P_PREFERRED_ID;
import com.ericsson.ssa.sip.PathNode.Type;
import com.ericsson.ssa.sip.dns.TargetTuple;
import com.ericsson.ssa.sip.transaction.ClientTransactionRegistrationListener;
import com.ericsson.ssa.sip.transaction.TransactionManager;

import org.jvnet.glassfish.comms.deployment.backend.SessionCase;
import org.jvnet.glassfish.comms.security.auth.impl.AuthInfoImpl;
import org.jvnet.glassfish.comms.security.auth.impl.ClientDigestCreator;
import org.jvnet.glassfish.comms.security.auth.impl.PAssertedAuthenticator;
import org.jvnet.glassfish.comms.security.auth.impl.PAssertedAuthenticatorFactory;
import org.jvnet.glassfish.comms.util.SipServletRequestFacade;

import java.io.BufferedReader;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.UnsupportedEncodingException;

import java.nio.ByteBuffer;

import java.security.cert.X509Certificate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.sip.Address;
import javax.servlet.sip.AuthInfo;
import javax.servlet.sip.B2buaHelper;
import javax.servlet.sip.Proxy;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.TooManyHopsException;
import javax.servlet.sip.UAMode;
import javax.servlet.sip.URI;
import javax.servlet.sip.ar.SipApplicationRoutingDirective;
import javax.servlet.sip.ar.SipApplicationRoutingRegion;


/**
* @author ekrigro
* @reviewed ejoelbi 2006-oct-19
*/
public class SipServletRequestImpl extends SipServletMessageImpl
    implements SipServletRequest, SipServletRequestFacade, Externalizable {
    /**
     * Comment for <code>serialVersionUID</code>
     */
    public static final String CLIENT_CERT = "javax.servlet.request.X509Certificate";
    private static final long serialVersionUID = 3257849874501548343L;
    private static final Set<String> _disallowedRecordRouteURIParams = new HashSet<String>();
    public static final List<String> NON_INITIAL_REQUEST_METHODS = Arrays.asList(new String[] {
                "CANCEL", "BYE", "PRACK", "ACK", "UPDATE", "INFO"
            });

    private static int debugResponse = -1;
    static {
        _disallowedRecordRouteURIParams.add("transport");
        _disallowedRecordRouteURIParams.add("lr");
        _disallowedRecordRouteURIParams.add("ttl");
        _disallowedRecordRouteURIParams.add("user");
        _disallowedRecordRouteURIParams.add("method");
        _disallowedRecordRouteURIParams.add("maddr");
        String s = System.getProperty("org.glassfish.sip.debugResponse");
        if (s != null) {
            s = s.trim();
            if (s.equals("*")) {
                debugResponse = 0;
            } else if (!s.equals("")){
                try {
                    debugResponse = Integer.parseInt(s);
                } catch (Exception e) {
                }
            }
        }
    }

    private static final Logger _logger = (Logger) Logger.getLogger(
            "SipContainer");

    private URI _requestURI;
    private boolean _isInitial = false;
    private ProxyContext _proxyContext = null;
    private boolean m_IsInPath = false;
    private SessionCase m_SessionCase = SessionCase.INTERNAL;
    private SipServletRequestImpl _transactionRequest = null;
    protected boolean _IsRecordRouteIndicated = false;
    protected boolean _IsPathIndicated = false;
    private volatile int _sentResponseCode = -1;
    private volatile boolean finalResponseGenerated = false;
    private int _rseq = 0;
    protected List<Dispatcher> _retransmission_applicationStack = null;
    private Address _poppedRoute = null;
    private volatile Address _initialPoppedRoute = null;
    private ArInfo _arInfo = new ArInfo(null, null);
    private SipServletRequestImpl _linkedRequest = null;
    private B2buaHelper _b2buahelper = null;
    private boolean _supervised = true;
    private Map<String, String> _recordRouteURIParams = new HashMap<String, String>(8);
    private Map<String, String> _pathURIParams = new HashMap<String, String>(8);
    private Map<String, String> _requestParams = new HashMap<String, String>(8);
    private boolean requestSent = false;
    private SipApplicationRoutingDirective _directive = SipApplicationRoutingDirective.NEW;
    private String transactionId;
    private volatile int timerC;
    private volatile boolean isFirstInvocation = true;
    private volatile boolean isRoutingDirectiveExplicitlySet = false;
    private transient SessionTarget st;

    // isNoCancel should not be copied in clone
    private volatile boolean isNoCancel = false;
    private String authInfoHeader = null;
    private int responseStatusCode = -1;
    private URI _subscriberURI;

    private List<Address> pushedRoutes = null;

    /**
     * Listener that gets callback if request is registered with ClientTransaction
     *
     */
    private ClientTransactionRegistrationListener clientTransactionRegistrationListener =
        null;
   
    // not need for synchronisation since a single thread will modify the list
  private transient List<TargetTuple> _failedTargets = new ArrayList<TargetTuple>();

    public SipServletRequestImpl() {
        super();
        _messageType = SipMessageType.SipRequest;
    }

    public SipServletRequestImpl(String method, URI requestURI, String protocol) {
        super(method, protocol);
        _requestURI = requestURI;
        _messageType = SipMessageType.SipRequest;
    }

    public boolean isNoCancel() {
        return isNoCancel;
    }

    public void setNoCancel() {
        isNoCancel = true;
    }

    public URI getRequestURI() {
        return _requestURI;
    }

    protected void addAuthInfoHeader(SipServletResponse response) {
        if (authInfoHeader != null) {
            response.addHeader(Header.AUTHENTICATION_INFO, authInfoHeader);
            this.authInfoHeader = null; //reset after being used.
        }
    }

    protected void setAuthInfoHeader(String value) {
        this.authInfoHeader = value;
    }

    public boolean isFirstInvocation() {
        return isFirstInvocation;
    }

    public void setFirstInvocation(boolean value) {
        isFirstInvocation = value;
    }

    /**
     * Returns that a Record Route header should be added to this response
     *
     * @return whether a Record Route header should be added
     */
    public boolean isRecordRouteIndicated() {
        return _IsRecordRouteIndicated;
    }

    /**
     * States that a Record Route header should be added to this response
     */
    public void indicateRecordRoute() {
        _IsRecordRouteIndicated = true;
    }

    /**
     * Set by the proxy branch to save the routes pushed to this request by AR
     */
    public void setPushedRouteList(List<Address> list) {
        this.pushedRoutes = list;
    }

    /**
     * return the pushed route list to proxy branch.
     */
    public List<Address> getPushedRouteList() {
        return this.pushedRoutes;
    }

    /**
     * Returns that a Path header should be added to this response
     *
     * @return whether a Path header should be added
     */
    public boolean isPathIndicated() {
        return _IsPathIndicated;
    }

    /**
     * States that a Path header should be added to this response
     */
    public void indicatePath() {
        _IsPathIndicated = true;
    }

    public void setRequestURI(URI requestURI) {
        if (requestURI == null) {
            throw new NullPointerException(
                "Not allowed to set null request URI");
        }

        _requestURI = requestURI;
    }

    // TEST for user centric
    public void writeExternal(ObjectOutput output) throws IOException {
        try {
            // Write the req uri
            output.writeObject(_requestURI); // TODO check write External on URI
                                             // classes
                                             // Let the Message class handle it's properties

            super.writeExternal(output);
        } catch (Exception ignore) {
        }
    }

    public void readExternal(ObjectInput input) throws IOException {
        try {
            _requestURI = (URI) input.readObject();
            super.readExternal(input);
        } catch (Exception ignore) {
        }
    }

    public Type isDirection() {
        if (isInitial()) {
            _Type = Type.Caller;

            return _Type;
        }

        return super.isDirection();
    }

    public void pushRoute(SipURI route) {
        Address routeAddress = _sf.createAddress(route);
        pushRoute(routeAddress);
    }

    public void pushRoute(Address routeAddress) {
        if (!isPushRouteAllowed()) {
            throw new IllegalStateException(
                "It is no support to call pushRoute in this state.");
        }

        if (headerMap.containsKey(Header.ROUTE)) {
            Header header = headerMap.get(Header.ROUTE);
            header.setAddressValue(routeAddress, true);
        } else {
            Header header = Header.createFormatted(Header.ROUTE, this);
            header.setAddressValue(routeAddress, true);
            headerMap.put(Header.ROUTE, header);
        }
        if (this.pushedRoutes != null) {
            this.pushedRoutes.add(routeAddress);
        }
    }

    public void pushPath(Address pathAddress) {
        if (!getMethod().equals("REGISTER")) {
            throw new IllegalStateException(
                "It's not allowed to call pushPath for non-REGISTER requests.");
        }

        //Verify that the REGISTER request has a Supported header containing path
        boolean pathSupported = false;
        ListIterator<String> supportedList = getHeaders(Header.SUPPORTED);
        String supported = null;

        while (supportedList.hasNext()) {
            supported = (String) supportedList.next();

            if (supported.equals("path")) {
                pathSupported = true;
            }
        }

        if (!pathSupported) {
            throw new IllegalStateException(
                "The REGISTER request is missing required option path in Supported header.");
        }

        if (headerMap.containsKey(Header.PATH)) {
            Header header = headerMap.get(Header.PATH);
            header.setAddressValue(pathAddress, true);
        } else {
            Header header = Header.createFormatted(Header.PATH, this);
            header.setAddressValue(pathAddress, true);
            headerMap.put(Header.PATH, header);
        }
    }

    public int getMaxForwards() {
        Header header = headerMap.get(Header.MAX_FORWARDS);

        if (header == null) {
            return -1;
        }

        String mf = header.getValue();

        if (mf == null) {
            return -1;
        }

        return Integer.parseInt(mf);
    }

    public void setMaxForwards(int nr) {
        // TODO Could be optimized since no pretty print is required in this
        // case
        if ((nr >= 0) && (nr <= 255)) {
            setPrettyHeader(Header.MAX_FORWARDS, String.valueOf(nr));
        } else {
            throw new IllegalArgumentException(
                "Argument is out of 0 - 255 range");
        }
    }

    public void setInitial(boolean isInitial) {
        if (NON_INITIAL_REQUEST_METHODS.contains(getMethod())) {
            // Ignore
            return;
        }

        _isInitial = isInitial;
    }

    public boolean isInitial() {
        return _isInitial;
    }

    public ServletInputStream getInputStream() throws IOException {
        // TODO Auto-generated method stub
        return null;
    }

    public BufferedReader getReader() throws IOException {
        // TODO Auto-generated method stub
        return null;
    }

    public void setInApplicationPath(boolean inPath) {
        m_IsInPath = inPath;
    }

    public boolean isInApplicationPath() {
        return m_IsInPath;
    }

    public ProxyContext getProxyContext() {
        return _proxyContext;
    }

    public void setProxyContext(ProxyContext proxyContext) {
        _proxyContext = proxyContext;
    }

    public Proxy getProxy() throws TooManyHopsException {
        return getProxy(true);
    }

    public Proxy getProxy(boolean create) throws TooManyHopsException {
        if (!isInitial()) {
            throw new IllegalStateException("Applications should not attempt " +
                "to explicitly proxy subsequent requests");
        }

        if (_b2buahelper != null) {
            throw new IllegalStateException("Only allowed to be B2bua");
        }

        if (headerMap.get(Header.MAX_FORWARDS).getValue().equals("0")) {
            throw new TooManyHopsException();
        }

        Proxy proxy = null;

        if (getProxyContext() == null) {
            if (isInApplicationPath()) {
                // support of SSA1.1, 10.2.3 Sending Responses (as a Proxy),
                // mandates to first fetch proxy before sending response
                throw new IllegalStateException("Only allowed to be UA");
            }

            if (create) {
                ProxyImpl proxyImpl = new ProxyImpl(getApplicationSessionImpl(),
                        this);
                setProxyContext(new ProxyContext(proxyImpl, getSessionImpl()));
                proxy = proxyImpl.getFacade(this);
            }
        } else {
            proxy = getProxyContext().getProxy().getFacade(this);
        }

        return proxy;
    }

    public SipServletResponse createResponse(int code)
        throws IllegalArgumentException, IllegalStateException {
        checkResponseCode(code);

        return createResponseImpl(code);
    }

    public SipServletResponseImpl createTerminatingResponse(int code) {
        // Don't send a terminating response, if the request was an 'ACK',
        // see TR HH52078
        if (getMethod().equals("ACK")) {
            return null;
        }

        SipServletResponseImpl resp = createResponseImpl(code);

        if (!resp.hasToTag()) {
            resp.createTag(Header.TO);
        }

        resp.setInitialRemote(getInitialRemote());
        // Temp fix which sets the remote target to avoid nullpointer in
        // NetworkManager
        // TODO Investigate if we should add the ResolverManager to the
        // transactionStack if
        // a response needs to be sent on the way up in the stack from a layer
        // below ResolverManager
        // (when ResolverManager is not yet pushed on the transactionStack)
        // If resolverManager is added it can handle reconnections through
        // firewalls (received/rport param)
        //
        resp.setRemote(getRemote());
        resp.setRequest(this); //To satisfy Proxy component if faled to send...
                               //TODO check if final proposal and why not in the createTerminatingResponse(int,String) method?
                               //Same for set remote!!! - Stoffe

        return resp;
    }

    public SipServletResponseImpl create100TryingResponse() {
        return createResponseImpl(100);
    }

    public SipServletResponseImpl createResponseImpl(int code) {
        return populateResponse(new SipServletResponseImpl(this,
                this.getProtocol(), code));
    }

    public SipServletResponse createResponse(int code, String phrase)
        throws IllegalArgumentException, IllegalStateException {
        checkResponseCode(code);

        return createResponseImpl(code, phrase);
    }

    public SipServletResponseImpl createTerminatingResponse(int code,
        String phrase) {
        // Don't send a terminating response, if the request was an 'ACK',
        // see TR HH52078
        if (getMethod().equals("ACK")) {
            return null;
        }

        SipServletResponseImpl resp = createResponseImpl(code, phrase);

        if (!resp.hasToTag()) {
            resp.createTag(Header.TO);
        }

        return resp;
    }

    public SipServletResponseImpl createResponseImpl(int code, String phrase) {
        return populateResponse(new SipServletResponseImpl(this,
                this.getProtocol(), code, phrase));
    }

    public SipServletRequest createCancel() {
        return createCancelImpl();
    }

    public SipServletRequestImpl createCancelImpl()
        throws IllegalStateException {
        if (getMethod().equals("INVITE")) {
            if ((responseStatusCode >= 200) && (getProxyContext() == null)) {
                throw new IllegalStateException(
                    " Already received final response ");
            }

            Address fromCopy = (Address) ((AddressImpl) getFromImpl()).clone(true,
                    true);
            Address toCopy = (Address) ((AddressImpl) getToImpl()).clone(true,
                    true);
            SipServletRequestImpl req = new SipServletRequestImpl("CANCEL",
                    getRequestURI(), SipFactoryImpl.PROTOCOL_LINE);

            // set To
            Header toHeader = new SingleLineHeader(Header.TO, true);
            toHeader.setAddressValue(toCopy, false);
            req.setHeader(toHeader);

            // set From
            Header fromHeader = new SingleLineHeader(Header.FROM, true);
            fromHeader.setAddressValue(fromCopy, false);
            req.setHeader(fromHeader);

            // set Max-Forwards
            Header maxForwardsHeader = new SingleLineHeader(Header.MAX_FORWARDS,
                    false);
            maxForwardsHeader.setValue("70", false);
            req.setHeader(maxForwardsHeader);

            // set CallID
            Header callIDHeader = new SingleLineHeader(Header.CALL_ID, true);
            callIDHeader.setValue(getCallId(), false);
            req.setHeader(callIDHeader);

            // set CSeq
            Header cSeqHeader = new SingleLineHeader(Header.CSEQ, true);
            cSeqHeader.setValue(Integer.toString(getCSeqNumber()) + " CANCEL",
                false);
            req.setHeader(cSeqHeader);

            // copy ROUTE of INVITE...
            Header route = getRawHeader(Header.ROUTE);

            if (route != null) {
                req.setHeader((Header) route.clone());
            }

            // update new request with session...
            req.setSession(getSessionImpl());
            // ...and dialog
            req.setDialog(getDialog());
            // find out direction
            req.setDirection(isDirection());
            // subsequent request
            req.setInitial(false);

            // Fetch the Application stack
            List<Layer> layers = LayerHandler.getInstance().getLayers();
            req._applicationStack.addAll(layers);
            // The destination address, port, and transport for the CANCEL MUST
            // be identical to those used to send the original request.
            req.setRemote(getRemote());
           
            copyNonSystemHeaders(req);

            return req;
        } else {
            throw new IllegalStateException(
                "Cancel is only allowed for INVITE.");
        }
    }
   
    /**
     * Copy all non-system headers from this message to the created request
     * @param req The request to which the headers are added.
     */
    protected void copyNonSystemHeaders(SipServletRequestImpl req) {
      String headerName = null;
      for(Iterator<String> headerNames = getHeaderNames() ; headerNames.hasNext();) {
        headerName = headerNames.next();
        if (headerName != null && ! Header.isSystemHeader(headerName, req)) {
          Header header = getRawHeader(headerName);
          if (header != null) {
            req.setHeader((Header) header.clone());
          }
        }
      }
  }

    public String getParameter(String name) {
        return _requestParams.get(name);
    }

    public Enumeration getParameterNames() {
        final Iterator<String> it = _requestParams.keySet().iterator();

        return new Enumeration<String>() {
                public boolean hasMoreElements() {
                    return it.hasNext();
                }

                public String nextElement() {
                    return it.next();
                }
            };
    }

    public String[] getParameterValues(String name) {
        return new String[] { _requestParams.get(name) };
    }

    public Map getParameterMap() {
        return Collections.unmodifiableMap(_requestParams);
    }

    public String getScheme() {
        return _requestURI.getScheme();
    }

    public String getServerName() {
        // Use information from getLocalAddr()....
        return getLocalAddr();
    }

    public int getServerPort() {
        // Use information from getLocalPort()....
        return getLocalPort();
    }

    public String getRemoteHost() {
        // Use information from getRemoteAddr()....
        return getRemoteAddr();
    }

    /**
     * Removes an attribute from the response.
     * This method should be moved to SipServletMessageImpl when SipServletMessage
     * is modified to contain the removeAttribute method.
     */
    public void removeAttribute(String name) {
        if (name == null) {
            throw new NullPointerException();
        }

        if (attrib != null) {
            attrib.remove(name);
        }
    }

    public Locale getLocale() {
        // Use information from getAcceptLanguage()....
        return getAcceptLanguage();
    }

    public Enumeration<Locale> getLocales() {
        // Use information from getAcceptLanguages()....
        final Iterator<Locale> it = getAcceptLanguages();

        return new Enumeration<Locale>() {
                public boolean hasMoreElements() {
                    return it.hasNext();
                }

                public Locale nextElement() {
                    return it.next();
                }
            };
    }

    public RequestDispatcher getRequestDispatcher(String name) {
        return new SipRequestDispatcher(name,
            SipFactoryImpl.getInstance().getServiceHandler());
    }

    @Deprecated
    public String getRealPath(String arg0) {
        // Shall return null in a SIP context
        return null;
    }

    public String getLocalName() {
        // Use information from getLocalAddr()....
        return getLocalAddr();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder(_method);
        sb.append(' ');
        sb.append(_requestURI);
        sb.append(' ');
        sb.append(SipFactoryImpl.PROTOCOL_LINE);
        sb.append(SipFactoryImpl.NEW_LINE);

        byte[] content = null;

        try {
            content = getRawContent();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        HashMap<String, Header> clonedHeaders = headerMap;

        if (headerForm == HeaderForm.COMPACT) {
            clonedHeaders = new HashMap<String, Header>(headerMap);

            for (String s : Header.LONG_TO_SHORT_MAP.keySet()) {
                if (clonedHeaders.containsKey(s)) {
                    Header h = clonedHeaders.get(s);
                    h.setName(Header.LONG_TO_SHORT_MAP.get(s));
                }
            }
        }

        Iterator<Header> i = clonedHeaders.values().iterator();

        while (i.hasNext()) {
            sb.append(i.next().toString());
        }

        sb.append(SipFactoryImpl.NEW_LINE);

        if ((content != null) && (content.length > 0)) {
            sb.append(new String(content));
        }

        return sb.toString();
    }

    //Returns the session target
    public SessionTarget getSessionTarget() {
        return this.st;
    }

    //Saves the Join/Replace SessionTarget handler
    void setSessionTarget(SessionTarget st) {
        this.st = st;
    }

    ByteBuffer toBufferFirstline(ByteBuffer bb)
        throws UnsupportedEncodingException {
        bb.put(_method.getBytes());
        bb.put((byte) 0x20);
        bb.put(_requestURI.toString().getBytes(SipFactoryImpl.SIP_CHARSET));
        bb.put((byte) 0x20);
        bb.put(SipFactoryImpl.PROTOCOL_LINE.getBytes());
        bb.put(SipFactoryImpl.NEW_LINE.getBytes());

        return bb;
    }

    public String toDebugString() {
        StringBuilder sb = new StringBuilder(_method);
        sb.append(" ");
        sb.append(_requestURI);
        sb.append(" ");
        sb.append(super.toDebugString());

        return sb.toString();
    }

    private SipServletResponseImpl populateResponse(
        SipServletResponseImpl response) {
        if (getMethod().equals("ACK")) {
            throw new IllegalStateException("Not allowed to create response " +
                response.getStatus() + " for ACK with callId = " + getCallId() +
                ", from = " + getFromImpl() + ", to = " + getToImpl());
        }

        int status = response.getStatus();
        if (debugResponse == status || debugResponse == 0) {
            _logger.warning("DEBUG CREATING RESPONSE for >> \n" + this);
            _logger.warning("DEBUG RESPONSE >> \n" + response);
            _logger.warning("DEBUG Thread dump follows >>");
            Thread.dumpStack();
        }

        Iterator<Header> i = headerMap.values().iterator();

        while (i.hasNext()) {
            Header next = i.next();

            if (next.equals(Header.VIA)) {
                response.headerMap.put(Header.VIA, (Header) next.clone());
            } else if (next.equals(Header.FROM)) {
                response.headerMap.put(Header.FROM, (Header) next.clone());
            } else if (next.equals(Header.TO)) {
                response.headerMap.put(Header.TO, (Header) next.clone());
            } // else if( next.equals( Header.P_ASSERTED_ID ) )
              // response.headerMap.put( Header.P_ASSERTED_ID,
              // (Header)next.clone()
              // );

            else if (next.equals(Header.CSEQ)) {
                response.headerMap.put(Header.CSEQ, (Header) next.clone());
            } else if (next.equals(Header.CALL_ID)) {
                response.headerMap.put(Header.CALL_ID, (Header) next.clone());
            } else if (next.equals(Header.RECORD_ROUTE)) {
                response.headerMap.put(Header.RECORD_ROUTE,
                    (Header) next.clone());
            } else if (next.equals(Header.EVENT)) {
                if ("SUBSCRIBE".equals(_method)) {
                   response.headerMap.put(Header.EVENT, (Header) next.clone());
                }
            }
        }

        // Dialog must be set before setting Contact
        response._dialog = _dialog;

        response._method = _method;
        response._transactionStack.addAll(_transactionStack);
        response._sf = _sf;
        response._local = _local;
        // response._remote = _remote; ........ no longer do this, HF85359
        response._session = _session;
        response.setDirection(isDirection());
        response.setBeKey(getBeKey());

        // Set Version information in Server header
        String version = System.getProperty("sip.module.version");

        if (version != null) {
            response.addHeader(Header.SERVER, version);
        }

        if (SipFactoryImpl.getContactRequirement(response) != HeaderRequirement.NOT_APPLICAPLE) {
            //As per JSR 289 section 4.1.3
            if (!SipFactoryImpl.contactAllowedFromServlet(response)) {
                populateContactHeader(response);
            }
        }

        // is this a feature of JSR 289 10.2.3 Sending Responses?
        if (isInitial() && (getProxyContext() != null)) {
            getProxyContext().getProxy().setVirtualProxyBranchRequest(response);
        }

        if (response.getStatus() >= 200) {
            finalResponseGenerated = true;
        }

        return response;
    }

    public void populateContactHeader(SipServletResponseImpl response) {
        dialogManager.addContact(response);

        // Specific code for JSR116 TCK to reuse the transport in record-route/contact
        // that a remote party sent, and include the same in the Contact header of the response.
        if ("INVITE".equals(_method) || "REFER".equals(_method) ||
                "SUBSCRIBE".equals(_method)) {
            try {
                // Check if Response has Record-Route headers
                Address rrouteAddress = getAddressHeaderImpl(Header.RECORD_ROUTE);
                SipURI sipuri = null;

                if ((rrouteAddress != null) &&
                        rrouteAddress.getURI().isSipURI()) {
                    // 1. Use transport from top-most Record Route on the incoming Request
                    sipuri = (SipURI) rrouteAddress.getURI();
                } else {
                    // 2. Use transport from Contact
                    URI remoteTarget = getAddressHeaderImpl("Contact").getURI();

                    if (remoteTarget.isSipURI()) {
                        sipuri = (SipURI) remoteTarget;
                    }
                }

                if ((sipuri != null) && (sipuri.getTransportParam() != null)) {
                    String transport = sipuri.getTransportParam();
                    Address contactAddress = response.getAddressHeaderImpl(Header.CONTACT);

                    if ((contactAddress != null) &&
                            contactAddress.getURI().isSipURI()) {
                        ((SipURI) contactAddress.getURI()).setTransportParam(transport);
                    }
                }
            } catch (Exception e) {
                // Should not happen, but consequences would be that the transport parameter is not set. 
            }
        }
    }

    public void send() throws IOException {
        validateMessageCommitted();

        if (getInitialRemote() != null) {
            throw new IllegalStateException("Incoming request cannot be send.");
        }

        DialogFragment p = getDialog();
        PathNode uac = null;
        //handleAssertedIdentity();

        if (isInitial()) {
            uac = new UA(getApplicationSessionImpl(), true);
            // add to application path
            p.addToPath(uac);
            // need to add to transaction path
            pushTransactionDispatcher(uac);
            // when this thread returns it should not continue...
            setSentOnThread(true);
        } else {
            // lets build the dispatcher list from the application path
            Iterator<PathNode> iter = null;

            if (isDirection() == Type.Caller) {
                iter = p.getCallee2CallerPath();
            } else if (isDirection() == Type.Callee) {
                iter = p.getCaller2CalleePath();
            } else {
                throw new IOException("Don't know the direction of the flow.");
            }

            // add the dispatchers
            while (iter.hasNext()) {
                uac = iter.next();
                SipSessionBase ss = uac.getSipSession();
                if (ss != null && ss.isValid()) {
                    pushApplicationDispatcher(uac);
                }
            }

            // last should not be stored because its the uac
            popDispatcher();
            // need to add to transaction path
            pushTransactionDispatcher(uac);
        }

        uac.send(this);
        requestSent = true;
    }

    public SessionCase getSessionCase() {
        return m_SessionCase;
    }

    public void setSessionCase(SessionCase sessionCase) {
        this.m_SessionCase = sessionCase;
    }

    public void removeSystemHeaders() {
        // remove system headers
        Iterator<String> i = Header.SYSTEM_HEADER_MAP.values().iterator();

        while (i.hasNext()) {
            headerMap.remove(i.next());
        }
    }
   
    public void removeRemoteSettings() {
        this._initialPoppedRoute = null;
        this._initialRemote = null;
        this._local = null;
    }

    public Object clone() {
        SipServletRequestImpl clone = new SipServletRequestImpl(getMethod(),
                getRequestURI(), getProtocol());
        Iterator<Header> i = headerMap.values().iterator();

        // deep copy
        while (i.hasNext()) {
            Header next = i.next();
            clone.headerMap.put(next.getName(), (Header) next.clone());
        }
        clone.setUserPrincipal(this.getUserPrincipal());
        clone.setUser(this.getRemoteUser());

        // Fix for issue#955, application attributes shall not be cloned
        // Note that when using SipRequestDispatcher.forward() the request
        // is not cloned and thus the attributes are available for the servlet
        // to which the request is forwarded.
        if (systemAttrib != null) {
            clone.systemAttrib = new HashMap<String, Object>(systemAttrib.size());
            clone.systemAttrib.putAll(systemAttrib);
        }

        // shallow copy
        clone.m_SessionCase = m_SessionCase;
        clone._content_enc = _content_enc;
        clone._content_byte = _content_byte;
        clone._content_obj = _content_obj;
        clone._roles = _roles;
        clone._initialRemote = _initialRemote;
        clone._remoteHop = _remoteHop;
        clone._remote = _remote;
        clone._local = _local;
        clone._isInitial = _isInitial;
        clone.isFirstInvocation = isFirstInvocation;
        clone._session = _session;
        clone._dialog = _dialog;
        clone._sf = _sf;
        clone._IsContactIndicated = _IsContactIndicated;
        clone._IsPathIndicated = _IsPathIndicated;
        clone._IsRecordRouteIndicated = _IsRecordRouteIndicated;
        clone._headersComplete = _headersComplete;
        clone._messageComplete = _messageComplete;
        clone.m_IsInPath = m_IsInPath;
        clone._rseq = _rseq;
        clone._fragmentId = _fragmentId;
        clone._supervised = _supervised;
        clone._recordRouteURIParams = _recordRouteURIParams;
        clone._pathURIParams = _pathURIParams;
        clone._requestParams = _requestParams;
        // JSR 289
        clone._initialPoppedRoute = _initialPoppedRoute;
        clone._poppedRoute = _poppedRoute;
        clone._arInfo = _arInfo;
        clone._directive = _directive;
        clone.timerC = timerC;
        clone.isRoutingDirectiveExplicitlySet = isRoutingDirectiveExplicitlySet;
        clone.oi = oi;
        clone._failedTargets = _failedTargets;

        // find out direction
        clone.setDirection(isDirection());


        // copy transaction and application stacks
        if (_transactionStack != null) {
            clone._transactionStack.addAll(_transactionStack);
        }

        if (_applicationStack != null) {
            clone._applicationStack.addAll(_applicationStack);
        }

        clone.setBeKey(getBeKey());

        return clone;
    }

    public void saveRetransmissionApplicationStack() {
        _retransmission_applicationStack = new ArrayList<Dispatcher>(_applicationStack);
    }

    public void restoreRetransmissionApplicationStack() {
        // if null or empty...
        if ((_applicationStack == null) ||
                ((_applicationStack != null) && _applicationStack.isEmpty())) {
            _applicationStack = new ArrayList<Dispatcher>(_retransmission_applicationStack);
        }
    }

    public Dispatcher popDispatcher() {
        int size = _applicationStack.size();

        if (size > 0) {
            return _applicationStack.remove(size - 1);
        }

        return null;
    }

    public Dispatcher peekDispatcher() {
        int size = _applicationStack.size();

        if (size > 0) {
            return _applicationStack.get(size - 1);
        }

        return null;
    }

    /**
     * Returns the request that should be used by the response when internally
     * traversing the path of the transaction or null if transaction path is
     * empty.
     *
     * @return the request used by the response when traversing the transaction
     *         path
     */
    public SipServletRequestImpl getTransactionRequest() {
        return _transactionRequest;
    }

    /**
     * Set the transaction request used by the response when travsersing the path
     * of the transaction.
     *
     * @param request
     *        the request mapped to the response
     */
    public void setTransactionRequest(SipServletRequestImpl request) {
        _transactionRequest = request;
    }

    public void setFragmentId(String id) {
        _fragmentId = id.toLowerCase();
    }

    /**
     * This method will be called by the reponse object at send operation. Sets
     * the indicator status code.
     *
     * @param status
     *        the indicator
     */
    public void setSentResponse(int statusCode) {
        _sentResponseCode = statusCode;
    }

    public boolean isSentResponse() {
        return _sentResponseCode != -1;
    }

    public boolean isSentFinalResponse2xx() {
        return (_sentResponseCode != -1) ? ((_sentResponseCode / 100) == 2)
                                         : false;
    }

    void setResponseStatusCode(int code) {
        responseStatusCode = code;
    }

    private boolean isValidStatusCode(int statusCode) {
        if (_sentResponseCode != -1) {
            if ((_sentResponseCode / 100) == 2) {
                if (!allowMultiple2xx()) {
                    return false;
                } else { // allow multiple 2xx

                    if ((statusCode / 100) != 2) {
                        // already sent 2xx final response,
                        // can't send non-2xx after...
                        return false;
                    }

                    // it's ok to send multiple 2xx with different to-tag
                }
            } else if ((_sentResponseCode / 100) > 2) {
                // already sent non-2xx final response
                return false;
            }
        }

        return true;
    }

    private boolean allowMultiple2xx() {
        return isB2buaHelper();
    }

    /*
     * This method will check for: 1. If we have already sent a final response
     * throw an IllegalStateException 2. If the status code out of range SIP
     * codes throw an IllegalArgumentException
     */
    private void checkResponseCode(int statusCode)
        throws IllegalArgumentException, IllegalStateException {
        if (!isValidStatusCode(statusCode)) {
            throw new IllegalStateException(
                "The request has already responded with a final response.");
        }

        if ((statusCode < 100) || (statusCode > 699)) {
            throw new IllegalArgumentException("Invalid SIP status code.");
        }
    }

    /**
     * Will return true for an INVITE request which support 100rel extension in a
     * Supported or Require header otherwise false.
     *
     * @return true for an INVITE request which support 100rel extension in a
     *         Supported or Require header otherwise false.
     */
    public boolean is100RelSupportedOrRequire() {
        if (getMethod().equals("INVITE")) {
            ListIterator supportedList = getHeaders(Header.SUPPORTED);
            String supported = null;

            while (supportedList.hasNext()) {
                supported = (String) supportedList.next();

                if (supported.equals(SipFactoryImpl.SUPPORTED_100REL)) {
                    return true;
                }
            }

            ListIterator requireList = getHeaders(Header.REQUIRE);
            String require = null;

            while (requireList.hasNext()) {
                require = (String) requireList.next();

                if (require.equals(SipFactoryImpl.SUPPORTED_100REL)) {
                    return true;
                }
            }
        }

        return false;
    }

    public int getAndIncrementRSeq() {
        return ++_rseq;
    }

    public void setPoppedRoute(Address route) {
        _poppedRoute = route;
    }

    public void setInitialPoppedRoute(Address a) {
        _initialPoppedRoute = a;
        _poppedRoute = a;
    }

    public Address getPoppedRoute() {
        if (_poppedRoute == null) {
            return null;
        }

        AddressImpl ai = (AddressImpl) _poppedRoute.clone();

        if (ai != null) {
            ai.setModifiable(isCommitted());
        }

        return ai;
    }

    public Address getInitialPoppedRoute() {
        if (_initialPoppedRoute == null) {
            return null;
        }

        AddressImpl ai = (AddressImpl) _initialPoppedRoute.clone();

        if (ai != null) {
            ai.setModifiable(isCommitted());
        }

        return ai;
    }

    public void setArInfo(ArInfo stateInfo) {
        _arInfo = stateInfo;
    }

    public ArInfo getArInfo() {
        return _arInfo;
    }

    public SipApplicationRoutingDirective getRoutingDirective()
        throws IllegalStateException {
        if (_isInitial) {
            return _directive;
        } else {
            throw new IllegalStateException("Not an initial request");
        }
    }

    public void setImplicitRoutingDirective(
        SipApplicationRoutingDirective directive, SipServletRequest origRequest) {
        if (!isRoutingDirectiveExplicitlySet) {
            setInternalRoutingDirective(directive, origRequest);
        } else {
            // assumes the application knows what it is doing..
            // TODO: this assumes once explcitly set never changed anymore
            // is this really correct?
            isRoutingDirectiveExplicitlySet = false;

            // do not change it, the first time
        }
    }

    public void setRoutingDirective(SipApplicationRoutingDirective directive,
        SipServletRequest origRequest) throws IllegalStateException {
        setInternalRoutingDirective(directive, origRequest);
        isRoutingDirectiveExplicitlySet = true;
    }

    public void resetExplicit() {
        isRoutingDirectiveExplicitlySet = false;
    }

    public void setInternalRoutingDirective(
        SipApplicationRoutingDirective directive, SipServletRequest origRequest)
        throws IllegalStateException {
        // If directive is NEW, origRequest parameter is ignored.
        if (SipApplicationRoutingDirective.NEW.equals(directive)) {
            _directive = directive;

            return;
        }

        // If directive if not NEW, we will try to copy the stateinfo from the
        // original request that is being passed in. JSR289 gives some hints on
        // how to do this, but it is not totally clear.
        if (origRequest == null) {
            // Just ignore it then, use whatever stateinfo we already have. For
            // example, stateinfo may have been cloned when this request was
            // constructed with the B2BUaHelper and some other original request.
            _directive = directive;

            return;
        }

        // JSR289 If directive is CONTINUE or REVERSE, the parameter origRequest
        // must be an initial request dispatched by the container to this
        // application, i.e. origRequest.isInitial() must be true.
        if (SipApplicationRoutingDirective.CONTINUE.equals(directive) ||
                SipApplicationRoutingDirective.REVERSE.equals(directive)) {
            if (!origRequest.isInitial()) {
                throw new IllegalStateException(
                    "You can only set a routing directive based on an initial" +
                    " request");
            }

            // This request must be a request created in a new SipSession or
            // from an initial request, and must not have been sent.
            if (!this._isInitial) {
                throw new IllegalStateException(
                    "You cannot set a routing directive on a request that is" +
                    " not initial.");
            }

            if (requestSent) {
                throw new IllegalStateException(
                    "You cannot set a routing directive on a request that has" +
                    " already been sent.");
            }

            // else set the directive and copy stateinfo
            // -- TODO JSR289 is not clear on this --
            this._directive = directive;

            if (origRequest instanceof SipServletRequestImpl) {
                this._arInfo = ((SipServletRequestImpl) origRequest).getArInfo();
            } else {
                _logger.warning(
                    "Could not copy state info (unknown type of origRequest)");
            }
        }
    }

    public SipServletRequestImpl getLinkedRequest() {
        return _linkedRequest;
    }

    public void setLinkedRequest(SipServletRequestImpl linkedRequest) {
        _linkedRequest = linkedRequest;
    }

    public B2buaHelper getB2buaHelper() {
        if (_proxyContext != null) {
            throw new IllegalStateException("Only allowed to be proxy");
        }

        if (_b2buahelper == null) {
            _b2buahelper = new B2buaHelperImpl(this);
        }

        if (isInitial() && !isCommitted() && !getSessionImpl().isB2buaHelper()) {
            // add this pending b2bua response
            getSessionImpl().createPendingMessageHelper();
            getSessionImpl().addPendingMessage(this, UAMode.UAS);
        }

        return _b2buahelper;
    }

    public void setB2buaHelper(B2buaHelper bua) {
        _b2buahelper = bua;
    }

    public boolean isB2buaHelper() {
        return _b2buahelper != null;
    }

    /**
     * Gets the supervise state of this request.
     * @return
     */
    public boolean getSupervised() {
        return _supervised;
    }

    /**
     * Sets the supervised state of this request.
     * @param supervised
     */
    public void setSupervised(boolean supervised) {
        _supervised = supervised;
    }

    public String getPathURIParam(String name) {
        return _pathURIParams.get(name);
    }

    public Iterator getPathURIParamNames() {
        return _pathURIParams.keySet().iterator();
    }

    public void removePathURIParam(String name) {
        _pathURIParams.remove(name);
    }

    public void setPathURIParam(String name, String value) {
        // Assume the same parameters are disallowed as for Record-Route
        if (!_disallowedRecordRouteURIParams.contains(name)) {
            _pathURIParams.put(name, value);
        } else {
            throw new IllegalArgumentException("Not allowed to set parameter '" +
                name + "' on Path URI.");
        }
    }

    public String getRecordRouteURIParam(String name) {
        return _recordRouteURIParams.get(name);
    }

    public Iterator getRecordRouteURIParamNames() {
        return _recordRouteURIParams.keySet().iterator();
    }

    public void removeRecordRouteURIParam(String name) {
        _recordRouteURIParams.remove(name);
    }

    public void setRecordRouteURIParam(String name, String value) {
        if (!_disallowedRecordRouteURIParams.contains(name)) {
            _recordRouteURIParams.put(name, value);
        } else {
            throw new IllegalArgumentException("Not allowed to set parameter '" +
                name + "' on Record-Route URI.");
        }
    }

    /**
     * Used on incoming requests to populate the parameters from the popped Route header
     * @param uri the URI to extract parameters from
     */
    public void setRecordRouteURI(URIImpl uri) {
        Iterator<String> iter;

        if (uri instanceof SipURIImpl) {
            iter = ((SipURIImpl) uri).getParameterNames();
        } else if (uri instanceof TelURLImpl) {
            iter = ((TelURLImpl) uri).getParameterNames();
        } else {
            return;
        }

        while (iter.hasNext()) {
            String name = iter.next();
            String value = uri.getParameter(name);

            if (!_disallowedRecordRouteURIParams.contains(name)) {
                // Put parameters in _requestParams map
                _requestParams.put(name, value);
            }
        }
    }

    /**
     * Used on incoming requests to populate the parameters from the request URI
     * @param uri the URI to extract parameters from
     */
    public void setRequestParams(URIImpl uri) {
        Iterator<String> iter;

        if (uri instanceof SipURIImpl) {
            iter = ((SipURIImpl) uri).getParameterNames();
        } else if (uri instanceof TelURLImpl) {
            iter = ((TelURLImpl) uri).getParameterNames();
        } else {
            return;
        }

        while (iter.hasNext()) {
            String name = iter.next();
            String value = uri.getParameter(name);
            // Put parameters in _requestParams map
            _requestParams.put(name, value);
        }
    }

    @Override
    public void setCertificate(X509Certificate[] cert) {
        super.setCertificate(cert);

        if (systemAttrib == null) {
            systemAttrib = new HashMap<String, Object>(8);
        }

        this.systemAttrib.put(CLIENT_CERT, cert);
    }

    public void addAuthHeader(SipServletResponse response, AuthInfo info) {
        if (response != null) {
            ClientDigestCreator cdc = new ClientDigestCreator();
            cdc.createDigest(info, this, response);
        }
    }

    public void addAuthHeader(SipServletResponse response, String username,
        String password) {
        AuthInfo ai = new AuthInfoImpl();
        Iterator<String> itr = response.getChallengeRealms();

        while (itr.hasNext()) {
            ai.addAuthInfo(response.getStatus(), itr.next(), username, password);
        }

        addAuthHeader(response, ai);
    }

    @Override
    public boolean isCommitted() {
        if (requestSent) {
            return true;
        }

        if (finalResponseGenerated) {
            return true;
        }

        if ((_sentResponseCode != -1) && ((_sentResponseCode / 100) > 1)) {
            return true;
        }

        return false;
    }

    public void handleAssertedIdentity() {
        ListIterator<String> passertedHeader = this.getHeaders(P_ASSERTED_ID);
        ListIterator<String> ppreferredHeader = this.getHeaders(P_PREFERRED_ID);

        if (passertedHeader.hasNext() || ppreferredHeader.hasNext()) {
            PAssertedAuthenticator auth = (PAssertedAuthenticator) PAssertedAuthenticatorFactory.getInstance()
                                                                                                .getAuthenticator();

            if (auth != null) {
                TargetTuple remoteHost = ((SipServletRequestImpl) this).getRemote();
                String host = "";

                if (remoteHost != null) {
                    host = remoteHost.getIP();
                }

                auth.verifyMessage(this, host);
            }
        }
    }

    public String getTransactionId() {
        if (getTransactionRequest() != null) {
            return getTransactionRequest().getTransactionId();
        } else {
            return transactionId;
        }
    }

    public void setTransactionId(String trId) {
        this.transactionId = trId;
    }

    public void setTimerC(int seconds) {
        this.timerC = seconds;
    }

    public int getTimerC() {
        return timerC;
    }

    /**
     * Pop the topmost Route header to simulate that request have exited and
     * re-entered.
     *
     * @param req
     *            the request to manipulate
     * @return true if route is popped, false otherwise
     */
    public Address popRouteHeader() {
        // loose route support: remove first route header
        Address poppedRoute = null;
        Header r = getRawHeader(Header.ROUTE);

        if (r != null) {
            r.setReadOnly(false);

            ListIterator<Address> it_a = null;

            try {
                it_a = r.getAddressValues();

                Address a = it_a.next();
                URIImpl uri = (URIImpl) a.getURI();

                if (uri.getLrParam()) {
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE, "Removing route = " + a);
                    }

                    it_a.remove();

                    // support of popped route added.                   
                    setRecordRouteURI(uri);

                    poppedRoute = a;
                }
            } catch (ServletParseException e) {
                // Should not happen
            }

            r.setReadOnly(true);
        }

        return poppedRoute;
    }

    /**
     * Examines the Route header of a request to determine if the request could
     * stay inside the container
     *
     * @param req
     *            the request to examine
     * @return true if route header exists and host part is "localhost" or
     *         "127.0.0.1", false otherwise
     */
    public boolean isLocalRoute() {
        // Check top Route header, if any
        try {
            AddressImpl route = (AddressImpl) getAddressHeaderImpl(Header.ROUTE);

            if (route != null) {
                return route.isLocal();
            } else {
                return false;
            }
        } catch (ServletParseException e) {
            // Should never occur.
            return false;
        }
    }

    public SipApplicationRoutingRegion getRegion() {
        if (_session != null) {
            return _session.getRegion();
        }

        return null;
    }

    public URI getSubscriberURI() {
        //What is directly set on request has
        //the precedence.
        if (_subscriberURI != null) {
            return _subscriberURI;
        } else if (_session != null) {
            return _session.getSubscriberURI();
        } else {
            //should not happen.
            return null;
        }
    }

    public void setSubscriberURI(URI u) {
         this._subscriberURI = u;
    }

    public void setRegion(SipApplicationRoutingRegion anRegion) {
        if (_session != null) {
            _session.setRegion(anRegion);
        }
    }

    public ClientTransactionRegistrationListener getClientTransactionRegistrationListener() {
        return clientTransactionRegistrationListener;
    }

    public void setClientTransactionRegistrationListener(
        ClientTransactionRegistrationListener clientTransactionListener) {
        this.clientTransactionRegistrationListener = clientTransactionListener;
    }

    /**
     * This method makes sure that the contact header does not break the specs.
     *
     * @throws ServletParseException
     */
    public void validateContact() throws ServletParseException
    {
        // 12.1.2 - If top route header or Request URI contains sips then
        // contact must be sips (UAC behaviour). We also extend this check
        // to take into account using sip uri scheme and transport=TLS.

        Header contactHeader;

        if (isContactIndicated() &&
                (contactHeader = getRawHeader(Header.CONTACT)) != null)
        {
            boolean secure = useSecureContact();

            AddressImpl contactAddress = (AddressImpl) contactHeader.getAddressValue();
            if (contactAddress != null &&
                    contactAddress.getURI() != null &&
                    contactAddress.getURI().isSipURI())
            {
                SipURI contactUri = (SipURI) contactAddress.getURI();

                contactUri.setPort(secure
                        ? dialogManager.getVipSipsUri().getPort()
                        : dialogManager.getVipSipUri().getPort());

                if (useSipsContact())
                {
                    // Use SIPS URI scheme
                    contactUri.setSecure(true);
                }
                else
                {
                    // Use SIP URI scheme
                    contactUri.setSecure(false);

                    if (secure)
                    {
                        contactUri.setTransportParam("tls");
                    }
                }
            }
        }
    }

    /**
     * Determines if the Contact header URI of a request sent
     * as UAC must be secure or not. The meaning of secure in this case
     * is defined by isUriSecure().
     *
     * @return True if and only if any route header is secure or the
     *  request URI is secure.
     */
    private boolean useSecureContact()
    {
        return isRouteHeaderSecure() || isRequestUriSecure();
    }

    /**
     * Determines if the Contact header URI of a request sent
     * as UAC must use the SIPS URI scheme or not.
     *
     * @return True if and only if any route header is using SIPS or the
     *  request URI is using SIPS.
     */
    private boolean useSipsContact()
    {
        return isRouteHeaderUsingSips() || isRequestUriUsingSips();
    }

    /**
     * Returns true if the Route header is present and the URI in the Route header
     * is secure according to isUriSecure().
     *
     * @return True if the Route header is present and the URI in the Route header
     * is secure according to isUriSecure(), otherwise false.
     */
    private boolean isRouteHeaderSecure()
    {
        Header r = getRawHeader(Header.ROUTE);
        if (r != null)
        {
            try
            {
                if (r.getAddressValue() != null)
                {
                    return isUriSecure(r.getAddressValue().getURI());
                }
            }
            catch (ServletParseException ignore)
            {
                // Do nothing
            }
        }

        return false;
    }

    /**
     * Returns true if the Route header is present and the URI in the Route header
     * is using SIPS URI scheme according to isUriUsingSips().
     *
     * @return True if the Route header is present and the URI in the Route header
     * is using SIPS URI scheme according to isUriUsingSips(), otherwise false.
     */
    private boolean isRouteHeaderUsingSips()
    {
        Header r = getRawHeader(Header.ROUTE);
        if (r != null)
        {
            try
            {
                if (r.getAddressValue() != null)
                {
                    return isUriUsingSips(r.getAddressValue().getURI());
                }
            }
            catch (ServletParseException ignore)
            {
                // Do nothing
            }
        }

        return false;
    }

    /**
     * Return true if the request URI is secure according to isUriSecure().
     *
     * @return True if the request URI is secure according to
     *  isUriSecure(), otherwise false.
     */
    private boolean isRequestUriSecure()
    {
        return isUriSecure(getRequestURI());
    }

    /**
     * Return true if the request URI is secure according to isUriUsingSips().
     *
     * @return True if the request URI is secure according to
     *  isUriUsingSips(), otherwise false.
     */
    private boolean isRequestUriUsingSips()
    {
        return isUriUsingSips(getRequestURI());
    }

    /**
     * Returns true if URI is a SipURI and either has the secure flag set
     * or has the transport parameter set to TLS.
     *
     * @param uri The URI to check.
     * @return True if URI is a SipURI and either has the secure flag set
     *  or has the transport parameter set to TLS, otherwise false.
     */
    private boolean isUriSecure(URI uri)
    {
        if (uri.isSipURI())
        {
            SipURI sipUri = (SipURI) uri;
            if (sipUri.isSecure() || (sipUri.getTransportParam() != null &&
                    sipUri.getTransportParam().equalsIgnoreCase("tls")))
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns true if URI is a SipURI and has the secure flag set.
     *
     * @param uri The URI to check.
     * @return True if URI is a SipURI and either has the secure flag set,
     *  otherwise false.
     */
    private boolean isUriUsingSips(URI uri)
    {
        if (uri.isSipURI())
        {
            SipURI sipUri = (SipURI) uri;
            return sipUri.isSecure();
        }

        return false;
    }

    private boolean isPushRouteAllowed() {
      return isInitial() || getDialog().size() == 1;
    }

    public void restoreRetransmissionApplicationStack(Layer currentLayer) {
        clearApplicationDispatchers();
        Iterator<Layer> iter =
        LayerHandler.getInstance().getLayers().iterator();
        Layer l = null;
         // lets iterate until and including ResolverManager...
         while (iter.hasNext()) {
             l = iter.next();
             if("CANCEL".equals(getMethod()) &&
                                        (l instanceof TransactionManager)) {
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE,
                           "TransactionManager not added for CANCEL " );
                    }
                 continue;
             }
             if (l.equals(currentLayer)) {
                 break;
             }
             pushApplicationDispatcher(l);
         }
     }

     public void popTopVia() {
            //Remove via
            Header reqvia = getRawHeader(Header.VIA);
            reqvia.setReadOnly(false);
            ListIterator<String> via_li = reqvia.getValues();
            String reqtopVia = via_li.next();
            // TODO could match to see that it's the right host'n port
            via_li.remove();
     }

  public List<TargetTuple> getFailedTargets() {
    return _failedTargets;
  }
 
  public void addFailedTarget(TargetTuple failedTarget) {
    _failedTargets.add(failedTarget);
  }
    
}
TOP

Related Classes of com.ericsson.ssa.sip.SipServletRequestImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.