private void sendUsingOutputStream(MessageContext msgContext) throws AxisFault {

    OMOutputFormat format = NhttpUtil.getOMOutputFormat(msgContext);
    MessageFormatter messageFormatter =
        MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
    OutputStream out = (OutputStream) msgContext.getProperty(MessageContext.TRANSPORT_OUT);

    if (msgContext.isServerSide()) {
      OutTransportInfo transportInfo =
          (OutTransportInfo) msgContext.getProperty(Constants.OUT_TRANSPORT_INFO);

      if (transportInfo != null) {
        transportInfo.setContentType(
            messageFormatter.getContentType(msgContext, format, msgContext.getSoapAction()));
      } else {
        throw new AxisFault(Constants.OUT_TRANSPORT_INFO + " has not been set");
      }
    }

    try {
      messageFormatter.writeTo(msgContext, format, out, false);
      out.close();
    } catch (IOException e) {
      handleException("IO Error sending response message", e);
    }
  }
  /**
   * transport sender invocation from Axis2 core
   *
   * @param msgContext message to be sent
   * @return the invocation response (always InvocationResponse.CONTINUE)
   * @throws AxisFault on error
   */
  public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {

    // remove unwanted HTTP headers (if any from the current message)
    removeUnwantedHeaders(msgContext);

    if (AddressingHelper.isReplyRedirected(msgContext)
        && !msgContext.getReplyTo().hasNoneAddress()) {

      msgContext.setProperty(NhttpConstants.IGNORE_SC_ACCEPTED, Constants.VALUE_TRUE);
    }

    EndpointReference epr = NhttpUtil.getDestinationEPR(msgContext);
    if (epr != null) {
      if (!epr.hasNoneAddress()) {
        sendAsyncRequest(epr, msgContext);
      } else {
        handleException("Cannot send message to " + AddressingConstants.Final.WSA_NONE_URI);
      }
    } else {

      if (msgContext.getProperty(Constants.OUT_TRANSPORT_INFO) != null) {
        if (msgContext.getProperty(Constants.OUT_TRANSPORT_INFO) instanceof ServerWorker) {
          sendAsyncResponse(msgContext);
        } else {
          sendUsingOutputStream(msgContext);
        }
      } else {
        handleException("No valid destination EPR or OutputStream to send message");
      }
    }

    if (msgContext.getOperationContext() != null) {
      msgContext
          .getOperationContext()
          .setProperty(Constants.RESPONSE_WRITTEN, Constants.VALUE_TRUE);
    }

    return InvocationResponse.CONTINUE;
  }
  /**
   * Send the passed in response message, asynchronously
   *
   * @param msgContext the message context to be sent
   * @throws AxisFault on error
   */
  private void sendAsyncResponse(MessageContext msgContext) throws AxisFault {

    int contentLength = extractContentLength(msgContext);

    // remove unwanted HTTP headers (if any from the current message)
    removeUnwantedHeaders(msgContext);
    Map transportHeaders = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);

    ServerWorker worker = (ServerWorker) msgContext.getProperty(Constants.OUT_TRANSPORT_INFO);
    HttpResponse response = worker.getResponse();

    OMOutputFormat format = NhttpUtil.getOMOutputFormat(msgContext);
    MessageFormatter messageFormatter =
        MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
    Boolean noEntityBody = (Boolean) msgContext.getProperty(NhttpConstants.NO_ENTITY_BODY);
    if (noEntityBody == null || Boolean.FALSE == noEntityBody) {
      response.setHeader(
          HTTP.CONTENT_TYPE,
          messageFormatter.getContentType(msgContext, format, msgContext.getSoapAction()));
    } else if (Boolean.TRUE == noEntityBody) {
      ((BasicHttpEntity) response.getEntity()).setChunked(false);
      ((BasicHttpEntity) response.getEntity()).setContentLength(0);

      // Since HTTP HEAD request doesn't contain message body content length of the is set to be 0.
      // To handle
      // content length 0 while serving head method, content length of the backend response is set
      // as the content
      // as synapse cannot calculate content length without providing message body.
      if (transportHeaders.get(NhttpConstants.HTTP_REQUEST_METHOD) != null
          && NhttpConstants.HTTP_HEAD.equals(
              transportHeaders.get(NhttpConstants.HTTP_REQUEST_METHOD))
          && transportHeaders.get(NhttpConstants.ORIGINAL_CONTENT_LEN) != null) {

        ((BasicHttpEntity) response.getEntity())
            .setContentLength(
                Long.parseLong(
                    String.valueOf(transportHeaders.get(NhttpConstants.ORIGINAL_CONTENT_LEN))));
        transportHeaders.remove(NhttpConstants.ORIGINAL_CONTENT_LEN);
        transportHeaders.remove(NhttpConstants.HTTP_REQUEST_METHOD);
      }
    }
    response.setStatusCode(determineHttpStatusCode(msgContext, response));

    // Override the Standard Reason Phrase
    if (msgContext.getProperty(NhttpConstants.HTTP_REASON_PHRASE) != null
        && !msgContext.getProperty(NhttpConstants.HTTP_REASON_PHRASE).equals("")) {
      response.setReasonPhrase(
          msgContext.getProperty(NhttpConstants.HTTP_REASON_PHRASE).toString());
    }

    // set any transport headers
    if (transportHeaders != null && !transportHeaders.values().isEmpty()) {
      Iterator iter = transportHeaders.keySet().iterator();
      while (iter.hasNext()) {
        Object header = iter.next();
        Object value = transportHeaders.get(header);
        if (value != null && header instanceof String && value instanceof String) {
          response.addHeader((String) header, (String) value);

          String excessProp = NhttpConstants.EXCESS_TRANSPORT_HEADERS;

          Map map = (Map) msgContext.getProperty(excessProp);
          if (map != null && map.get(header) != null) {
            log.debug(
                "Number of excess values for "
                    + header
                    + " header is : "
                    + ((Collection) (map.get(header))).size());

            for (Iterator iterator = map.keySet().iterator(); iterator.hasNext(); ) {
              String key = (String) iterator.next();

              for (String excessVal : (Collection<String>) map.get(key)) {
                if (header.equals(key)) {
                  response.addHeader((String) header, (String) excessVal);
                }
              }
            }
          }
        }
      }
    }

    boolean forceContentLength =
        msgContext.isPropertyTrue(NhttpConstants.FORCE_HTTP_CONTENT_LENGTH);
    boolean forceContentLengthCopy =
        msgContext.isPropertyTrue(NhttpConstants.COPY_CONTENT_LENGTH_FROM_INCOMING);

    BasicHttpEntity entity = (BasicHttpEntity) response.getEntity();

    MetricsCollector lstMetrics = worker.getServiceHandler().getMetrics();
    try {
      if (forceContentLength) {
        entity.setChunked(false);
        if (forceContentLengthCopy && contentLength > 0) {
          entity.setContentLength(contentLength);
        } else {
          setStreamAsTempData(entity, messageFormatter, msgContext, format);
        }
      }

      worker.getServiceHandler().commitResponse(worker.getConn(), response);
      lstMetrics.reportResponseCode(response.getStatusLine().getStatusCode());
      OutputStream out = worker.getOutputStream();

      /*
       * if this is a dummy message to handle http 202 case with non-blocking IO
       * write an empty byte array as body
       */
      if (msgContext.isPropertyTrue(NhttpConstants.SC_ACCEPTED) || Boolean.TRUE == noEntityBody) {
        out.write(new byte[0]);
      } else {
        if (forceContentLength) {
          if (forceContentLengthCopy && contentLength > 0) {
            messageFormatter.writeTo(msgContext, format, out, false);
          } else {
            writeMessageFromTempData(out, msgContext);
          }
        } else {
          messageFormatter.writeTo(msgContext, format, out, false);
        }
      }
      out.close();
      if (lstMetrics != null) {
        lstMetrics.incrementMessagesSent();
      }

    } catch (ProtocolException e) {
      log.error(e + " (Synapse may be trying to send an exact response more than once )");
    } catch (HttpException e) {
      if (lstMetrics != null) {
        lstMetrics.incrementFaultsSending();
      }
      handleException(
          "Unexpected HTTP protocol error sending response to : " + worker.getRemoteAddress(), e);
    } catch (ConnectionClosedException e) {
      if (lstMetrics != null) {
        lstMetrics.incrementFaultsSending();
      }
      log.warn("Connection closed by client : " + worker.getRemoteAddress());
    } catch (IllegalStateException e) {
      if (lstMetrics != null) {
        lstMetrics.incrementFaultsSending();
      }
      log.warn("Connection closed by client : " + worker.getRemoteAddress());
    } catch (IOException e) {
      if (lstMetrics != null) {
        lstMetrics.incrementFaultsSending();
      }
      handleException("IO Error sending response message to : " + worker.getRemoteAddress(), e);
    } catch (Exception e) {
      if (lstMetrics != null) {
        lstMetrics.incrementFaultsSending();
      }
      handleException(
          "General Error sending response message to : " + worker.getRemoteAddress(), e);
    }

    InputStream is = worker.getIs();
    if (is != null) {
      try {
        is.close();
      } catch (IOException ignore) {
      }
    }
  }
Example #4
0
  /** Process the incoming request */
  @SuppressWarnings({"unchecked"})
  public void run() {

    String method = request.getRequestLine().getMethod().toUpperCase();
    msgContext.setProperty(
        Constants.Configuration.HTTP_METHOD, request.getRequestLine().getMethod());

    if (NHttpConfiguration.getInstance().isHttpMethodDisabled(method)) {
      handleException("Unsupported method : " + method, null);
    }

    // String uri = request.getRequestLine().getUri();
    String oriUri = request.getRequestLine().getUri();
    String restUrlPostfix = NhttpUtil.getRestUrlPostfix(oriUri, cfgCtx.getServicePath());

    msgContext.setProperty(NhttpConstants.REST_URL_POSTFIX, restUrlPostfix);
    String servicePrefix = oriUri.substring(0, oriUri.indexOf(restUrlPostfix));
    if (servicePrefix.indexOf("://") == -1) {
      HttpInetConnection inetConn = (HttpInetConnection) conn;
      InetAddress localAddr = inetConn.getLocalAddress();
      if (localAddr != null) {
        servicePrefix =
            schemeName
                + "://"
                + localAddr.getHostName()
                + ":"
                + inetConn.getLocalPort()
                + servicePrefix;
      }

      if (inetConn.getLocalPort() > 0) {
        msgContext.setProperty(NhttpConstants.SERVER_PORT, inetConn.getLocalPort());
      }
    }
    msgContext.setProperty(NhttpConstants.SERVICE_PREFIX, servicePrefix);

    if ("GET".equals(method)) {
      httpGetRequestProcessor.process(request, response, msgContext, conn, os, isRestDispatching);
    } else if ("POST".equals(method)) {
      processEntityEnclosingMethod();
    } else if ("PUT".equals(method)) {
      processEntityEnclosingMethod();
    } else if ("HEAD".equals(method)) {
      processNonEntityEnclosingMethod();
    } else if ("OPTIONS".equals(method)) {
      processNonEntityEnclosingMethod();
    } else if ("DELETE".equals(method)) {
      processGetAndDelete("DELETE");
    } else if ("TRACE".equals(method)) {
      processNonEntityEnclosingMethod();
    } else {
      handleException("Unsupported method : " + method, null);
    }

    // here the RequestResponseTransport plays an important role when it comes to
    // dual channel invocation. This is becasue we need to ACK to the request once the request
    // is received to synapse. Otherwise we will not be able to support the single channel
    // invocation within the actual service and synapse for a dual channel request from the
    // client.
    if (isAckRequired()) {
      String respWritten = "";
      if (msgContext.getOperationContext() != null) {
        respWritten =
            (String) msgContext.getOperationContext().getProperty(Constants.RESPONSE_WRITTEN);
      }
      boolean respWillFollow =
          !Constants.VALUE_TRUE.equals(respWritten) && !"SKIP".equals(respWritten);
      boolean acked =
          (((RequestResponseTransport)
                      msgContext.getProperty(RequestResponseTransport.TRANSPORT_CONTROL))
                  .getStatus()
              == RequestResponseTransport.RequestResponseTransportStatus.ACKED);
      boolean forced = msgContext.isPropertyTrue(NhttpConstants.FORCE_SC_ACCEPTED);
      boolean nioAck = msgContext.isPropertyTrue("NIO-ACK-Requested", false);

      if (respWillFollow || acked || forced || nioAck) {

        if (!nioAck) {
          if (log.isDebugEnabled()) {
            log.debug(
                "Sending 202 Accepted response for MessageID : "
                    + msgContext.getMessageID()
                    + " response written : "
                    + respWritten
                    + " response will follow : "
                    + respWillFollow
                    + " acked : "
                    + acked
                    + " forced ack : "
                    + forced);
          }
          response.setStatusCode(HttpStatus.SC_ACCEPTED);
        } else {
          if (log.isDebugEnabled()) {
            log.debug(
                "Sending ACK response with status "
                    + msgContext.getProperty(NhttpConstants.HTTP_SC)
                    + ", for MessageID : "
                    + msgContext.getMessageID());
          }
          response.setStatusCode(
              Integer.parseInt(msgContext.getProperty(NhttpConstants.HTTP_SC).toString()));
          Map<String, String> responseHeaders =
              (Map<String, String>) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
          if (responseHeaders != null) {
            for (String headerName : responseHeaders.keySet()) {
              response.addHeader(headerName, responseHeaders.get(headerName));

              String excessProp = NhttpConstants.EXCESS_TRANSPORT_HEADERS;

              Map map = (Map) msgContext.getProperty(excessProp);
              if (map != null) {
                log.debug(
                    "Number of excess values for "
                        + headerName
                        + " header is : "
                        + ((Collection) (map.get(headerName))).size());

                for (Iterator iterator = map.keySet().iterator(); iterator.hasNext(); ) {
                  String key = (String) iterator.next();

                  for (String excessVal : (Collection<String>) map.get(key)) {
                    response.addHeader(headerName, (String) excessVal);
                  }
                }
              }
            }
          }
        }

        if (metrics != null) {
          metrics.incrementMessagesSent();
        }

        try {

          /*
           * Remove Content-Length and Transfer-Encoding headers, if already present.
           * */
          response.removeHeaders(HTTP.TRANSFER_ENCODING);
          response.removeHeaders(HTTP.CONTENT_LEN);

          serverHandler.commitResponse(conn, response);

        } catch (HttpException e) {
          if (metrics != null) {
            metrics.incrementFaultsSending();
          }
          handleException("Unexpected HTTP protocol error : " + e.getMessage(), e);
        } catch (ConnectionClosedException e) {
          if (metrics != null) {
            metrics.incrementFaultsSending();
          }
          log.warn("Connection closed by client (Connection closed)");
        } catch (IllegalStateException e) {
          if (metrics != null) {
            metrics.incrementFaultsSending();
          }
          log.warn("Connection closed by client (Buffer closed)");
        } catch (IOException e) {
          if (metrics != null) {
            metrics.incrementFaultsSending();
          }
          handleException("IO Error sending response message", e);
        } catch (Exception e) {
          if (metrics != null) {
            metrics.incrementFaultsSending();
          }
          handleException("General Error sending response message", e);
        }

        if (is != null) {
          try {
            is.close();
          } catch (IOException ignore) {
          }
        }

        // make sure that the output stream is flushed and closed properly
        try {
          os.flush();
          os.close();
        } catch (IOException ignore) {
        }
      }
    }
  }
Example #5
0
  /**
   * Create an Axis2 message context for the given http request. The request may be in the process
   * of being streamed
   *
   * @param request the http request to be used to create the corresponding Axis2 message context
   * @return the Axis2 message context created
   */
  private MessageContext createMessageContext(HttpRequest request) {

    MessageContext msgContext = new MessageContext();
    msgContext.setMessageID(UIDGenerator.generateURNString());

    // There is a discrepency in what I thought, Axis2 spawns a new threads to
    // send a message if this is TRUE - and I want it to be the other way
    msgContext.setProperty(MessageContext.CLIENT_API_NON_BLOCKING, Boolean.FALSE);
    msgContext.setConfigurationContext(cfgCtx);
    if ("https".equalsIgnoreCase(schemeName)) {
      msgContext.setTransportOut(
          cfgCtx.getAxisConfiguration().getTransportOut(Constants.TRANSPORT_HTTPS));
      msgContext.setTransportIn(
          cfgCtx.getAxisConfiguration().getTransportIn(Constants.TRANSPORT_HTTPS));
      msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTPS);
      SSLIOSession session = (SSLIOSession) (conn.getContext()).getAttribute("SSL_SESSION");
      msgContext.setProperty(
          "ssl.client.auth.cert.X509", session.getAttribute("ssl.client.auth.cert.X509"));

    } else {
      msgContext.setTransportOut(
          cfgCtx.getAxisConfiguration().getTransportOut(Constants.TRANSPORT_HTTP));
      msgContext.setTransportIn(
          cfgCtx.getAxisConfiguration().getTransportIn(Constants.TRANSPORT_HTTP));
      msgContext.setIncomingTransportName(Constants.TRANSPORT_HTTP);
    }
    msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, this);
    // the following statement causes the soap session services to be failing - ruwan
    // msgContext.setServiceGroupContextId(UUIDGenerator.getUUID());
    msgContext.setServerSide(true);
    msgContext.setProperty(
        Constants.Configuration.TRANSPORT_IN_URL, request.getRequestLine().getUri());

    // http transport header names are case insensitive
    Map<String, String> headers =
        new TreeMap<String, String>(
            new Comparator<String>() {
              public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
              }
            });

    for (Header header : request.getAllHeaders()) {

      String headerName = header.getName();

      // if this header is already added
      if (headers.containsKey(headerName)) {
        /* this is a multi-value header */
        // generate the key
        String key = NhttpConstants.EXCESS_TRANSPORT_HEADERS;
        // get the old value
        String oldValue = headers.get(headerName);
        // adds additional values to a list in a property of message context
        Map map;
        if (msgContext.getProperty(key) != null) {
          map = (Map) msgContext.getProperty(key);
          map.put(headerName, oldValue);
        } else {
          map = new MultiValueMap();
          map.put(headerName, oldValue);
          // set as a property in message context
          msgContext.setProperty(key, map);
        }
      }
      headers.put(header.getName(), header.getValue());
    }
    msgContext.setProperty(MessageContext.TRANSPORT_HEADERS, headers);

    // find the remote party IP address and set it to the message context
    if (conn instanceof HttpInetConnection) {
      HttpInetConnection inetConn = (HttpInetConnection) conn;
      InetAddress remoteAddr = inetConn.getRemoteAddress();
      if (remoteAddr != null) {
        msgContext.setProperty(MessageContext.REMOTE_ADDR, remoteAddr.getHostAddress());
        msgContext.setProperty(NhttpConstants.REMOTE_HOST, NhttpUtil.getHostName(remoteAddr));
        remoteAddress = remoteAddr.getHostAddress();
      }
    }

    msgContext.setProperty(
        RequestResponseTransport.TRANSPORT_CONTROL,
        new HttpCoreRequestResponseTransport(msgContext));

    msgContext.setProperty(
        ServerHandler.SERVER_CONNECTION_DEBUG,
        conn.getContext().getAttribute(ServerHandler.SERVER_CONNECTION_DEBUG));

    msgContext.setProperty(NhttpConstants.NHTTP_INPUT_STREAM, is);
    msgContext.setProperty(NhttpConstants.NHTTP_OUTPUT_STREAM, os);

    return msgContext;
  }