blob: f9f5080d32a79d2ab51cc42eeab0e4303bb321dc [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.messaging.channels
{
COMPILE::SWF
{
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.ErrorEvent;
import flash.events.TimerEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLVariables;
import flash.events.HTTPStatusEvent;
}
COMPILE::JS
{
import org.apache.royale.events.Event;
import mx.events.IOErrorEvent;
import mx.events.ErrorEvent;
import mx.events.SecurityErrorEvent;
import org.apache.royale.events.EventDispatcher;
import org.apache.royale.net.URLLoader;
import org.apache.royale.net.URLRequest;
import org.apache.royale.net.URLRequestHeader;
import mx.events.HTTPStatusEvent;
}
import mx.core.mx_internal;
import mx.messaging.Channel;
import mx.messaging.MessageAgent;
import mx.messaging.MessageResponder;
import mx.messaging.errors.ChannelError;
import mx.messaging.errors.InvalidChannelError;
import mx.messaging.errors.MessageSerializationError;
import mx.messaging.messages.AcknowledgeMessage;
import mx.messaging.messages.ErrorMessage;
import mx.messaging.messages.HTTPRequestMessage;
import mx.messaging.messages.IMessage;
import mx.messaging.config.LoaderConfig;
import mx.netmon.NetworkMonitor;
import mx.resources.IResourceManager;
import mx.resources.ResourceManager;
use namespace mx_internal;
//[ResourceBundle("messaging")]
[ExcludeClass]
/**
* @private
* The DirectHTTPChannel class is used to turn an HTTPRequestMessage object into an
* HTTP request.
* This Channel does not connect to a Flex endpoint.
*/
public class DirectHTTPChannel extends Channel
{
/**
* Constructs an instance of a DirectHTTPChannel.
* The parameters are not used.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
public function DirectHTTPChannel(id:String, uri:String="")
{
super(id, uri);
if (uri.length > 0)
{
var message:String = resourceManager.getString(
"messaging", "noURIAllowed");
throw new InvalidChannelError(message);
}
clientId = ("DirectHTTPChannel" + clientCounter++);
}
/**
* @private
* Used by DirectHTTPMessageResponder to specify a dummy clientId for AcknowledgeMessages.
* Each instance of this channel gets a new clientId.
*/
mx_internal var clientId:String;
/**
* @private
*/
private var resourceManager:IResourceManager =
ResourceManager.getInstance();
/**
* Indicates if this channel is connected.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
override public function get connected():Boolean
{
return true;
}
/**
* Indicates the protocol used by this channel.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
override public function get protocol():String
{
return "http";
}
//----------------------------------
// realtime
//----------------------------------
/**
* @private
* Returns true if the channel supports realtime behavior via server push or client poll.
*/
override mx_internal function get realtime():Boolean
{
return false;
}
/**
* @private
* Because this channel is always "connected", we ignore any connect timeout
* that is reported.
*/
/*
override protected function connectTimeoutHandler(event:TimerEvent):void
{
// Ignore.
}
*/
/**
* Returns the appropriate MessageResponder for the Channel.
*
* @param agent The MessageAgent sending the message.
*
* @param message The IMessage to send.
*
* @return The MessageResponder to handle the send result or fault.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
override protected function getMessageResponder(agent:MessageAgent,
message:IMessage):MessageResponder
{
return new DirectHTTPMessageResponder(agent, message, this, new URLLoader());
}
/**
* Because this channel doesn't participate in hunting we will always assume
* that we have connected.
*
* @private
*/
override protected function internalConnect():void
{
connectSuccess();
}
override protected function internalSend(msgResp:MessageResponder):void
{
var httpMsgResp:DirectHTTPMessageResponder = DirectHTTPMessageResponder(msgResp);
var urlRequest:URLRequest;
try
{
urlRequest = createURLRequest(httpMsgResp.message);
}
catch(e: MessageSerializationError)
{
httpMsgResp.agent.fault(e.fault, httpMsgResp.message);
return;
}
var urlLoader:URLLoader = httpMsgResp.urlLoader;
urlLoader.addEventListener(ErrorEvent.ERROR, httpMsgResp.errorHandler);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, httpMsgResp.errorHandler);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, httpMsgResp.securityErrorHandler);
urlLoader.addEventListener(Event.COMPLETE, httpMsgResp.completeHandler);
urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpMsgResp.httpStatusHandler);
urlLoader.load(urlRequest);
}
/**
* @private
*/
/*override */
mx_internal function createURLRequest(message:IMessage):URLRequest
{
var httpMsg:HTTPRequestMessage = HTTPRequestMessage(message);
var result:URLRequest = new URLRequest();
var url:String = httpMsg.url;
var params:String = null;
// Propagate our requestTimeout for those platforms
// supporting the idleTimeout property on URLRequest.
if ("idleTimeout" in result && requestTimeout > 0)
result["idleTimeout"] = requestTimeout * 1000;
result.contentType = httpMsg.contentType;
var contentTypeIsXML:Boolean =
result.contentType == HTTPRequestMessage.CONTENT_TYPE_XML
|| result.contentType == HTTPRequestMessage.CONTENT_TYPE_SOAP_XML;
var headers:Object = httpMsg.httpHeaders;
if (headers)
{
var requestHeaders:Array = [];
var header:URLRequestHeader;
for (var h:String in headers)
{
header = new URLRequestHeader(h, headers[h]);
requestHeaders.push(header);
}
result.requestHeaders = requestHeaders;
}
if (!contentTypeIsXML)
{
COMPILE::SWF {
var urlVariables:flash.net.URLVariables = new flash.net.URLVariables();
}
COMPILE::JS {
var urlVariables:URLVariables = new URLVariables();
}
var body:Object = httpMsg.body;
for (var p:String in body)
urlVariables[p] = httpMsg.body[p];
params = urlVariables.toString();
}
if (httpMsg.method == HTTPRequestMessage.POST_METHOD || contentTypeIsXML)
{
result.method = "POST";
if (result.contentType == HTTPRequestMessage.CONTENT_TYPE_FORM)
result.data = params;
else
{
// For XML content, work around bug 196450 by calling
// XML.toXMLString() ourselves as URLRequest.data uses
// XML.toString() hence bug 184950.
if (httpMsg.body != null && httpMsg.body is XML)
result.data = XML(httpMsg.body).toXMLString();
else
result.data = httpMsg.body;
}
}
else
{
if (params && params != "")
{
url += (url.indexOf("?") > -1) ? '&' : '?';
url += params;
}
}
result.url = url;
if (NetworkMonitor.isMonitoring())
{
// NetworkMonitor.adjustURLRequest(result, LoaderConfig.url, message.messageId);
}
return result;
}
override public function setCredentials(credentials:String, agent:MessageAgent=null, charset:String=null):void
{
var message:String = resourceManager.getString(
"messaging", "authenticationNotSupported");
throw new ChannelError(message);
}
/**
* @private
* Incremented per new instance of the channel to create clientIds.
*/
private static var clientCounter:uint;
}
}
COMPILE::SWF
{
import flash.events.Event;
import flash.events.ErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.events.HTTPStatusEvent;
}
COMPILE::JS
{
import org.apache.royale.events.Event;
import mx.events.ErrorEvent;
import mx.events.IOErrorEvent;
import mx.events.SecurityErrorEvent;
import org.apache.royale.net.URLLoader;
import mx.events.HTTPStatusEvent;
}
import mx.core.mx_internal;
import mx.messaging.MessageAgent;
import mx.messaging.MessageResponder;
import mx.messaging.channels.DirectHTTPChannel;
import mx.messaging.messages.AbstractMessage;
import mx.messaging.messages.AcknowledgeMessage;
import mx.messaging.messages.HTTPRequestMessage;
import mx.messaging.messages.ErrorMessage;
import mx.messaging.messages.IMessage;
import mx.resources.IResourceManager;
import mx.resources.ResourceManager;
use namespace mx_internal;
[ResourceBundle("messaging")]
/**
* @private
* This is an adapter for url loader that is used by the HTTPChannel.
*/
class DirectHTTPMessageResponder extends MessageResponder
{
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructs a DirectHTTPMessageResponder.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
public function DirectHTTPMessageResponder(agent:MessageAgent, msg:IMessage,
channel:DirectHTTPChannel, urlLoader:URLLoader)
{
super(agent, msg, channel);
this.urlLoader = urlLoader;
clientId = channel.clientId;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var clientId:String;
/**
* @private
*/
private var lastStatus:int;
/**
* @private
*/
private var resourceManager:IResourceManager = ResourceManager.getInstance();
/**
* The URLLoader associated with this responder.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
public var urlLoader:URLLoader;
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
public function errorHandler(event:Event):void
{
status(null);
// send the ack
var ack:AcknowledgeMessage = new AcknowledgeMessage();
ack.clientId = clientId;
ack.correlationId = message.messageId;
ack.headers[AcknowledgeMessage.ERROR_HINT_HEADER] = true; // hint there was an error
agent.acknowledge(ack, message);
// send fault
var msg:ErrorMessage = new ErrorMessage();
msg.clientId = clientId;
msg.correlationId = message.messageId;
msg.faultCode = "Server.Error.Request";
msg.faultString = resourceManager.getString(
"messaging", "httpRequestError");
var details:String = event.toString();
if (message is HTTPRequestMessage)
{
details += ". URL: ";
details += HTTPRequestMessage(message).url;
}
msg.faultDetail = resourceManager.getString(
"messaging", "httpRequestError.details", [ details ]);
msg.rootCause = event;
msg.body = URLLoader(event.target).data;
msg.headers[AbstractMessage.STATUS_CODE_HEADER] = lastStatus;
agent.fault(msg, message);
}
/**
* @private
*/
public function securityErrorHandler(event:Event):void
{
status(null);
// send the ack
var ack:AcknowledgeMessage = new AcknowledgeMessage();
ack.clientId = clientId;
ack.correlationId = message.messageId;
ack.headers[AcknowledgeMessage.ERROR_HINT_HEADER] = true; // hint there was an error
agent.acknowledge(ack, message);
// send fault
var msg:ErrorMessage = new ErrorMessage();
msg.clientId = clientId;
msg.correlationId = message.messageId;
msg.faultCode = "Channel.Security.Error";
msg.faultString = resourceManager.getString(
"messaging", "securityError");
msg.faultDetail = resourceManager.getString(
"messaging", "securityError.details", [ message.destination ]);
msg.rootCause = event;
msg.body = URLLoader(event.target).data;
msg.headers[AbstractMessage.STATUS_CODE_HEADER] = lastStatus;
agent.fault(msg, message);
}
/**
* @private
*/
public function completeHandler(event:Event):void
{
result(null);
var ack:AcknowledgeMessage = new AcknowledgeMessage();
ack.clientId = clientId;
ack.correlationId = message.messageId;
ack.body = URLLoader(event.target).data;
ack.headers[AbstractMessage.STATUS_CODE_HEADER] = lastStatus;
agent.acknowledge(ack, message);
}
/**
* @private
*/
public function httpStatusHandler(event:HTTPStatusEvent):void
{
COMPILE::SWF {
lastStatus = event.status;
}
}
/**
* Handle a request timeout by closing our associated URLLoader and
* faulting the message to the agent.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion BlazeDS 4
* @productversion LCDS 3
*/
override protected function requestTimedOut():void
{
urlLoader.removeEventListener(ErrorEvent.ERROR, errorHandler);
urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
urlLoader.removeEventListener(Event.COMPLETE, completeHandler);
urlLoader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
// urlLoader.close();
status(null);
// send the ack
var ack:AcknowledgeMessage = new AcknowledgeMessage();
ack.clientId = clientId;
ack.correlationId = message.messageId;
ack.headers[AcknowledgeMessage.ERROR_HINT_HEADER] = true; // hint there was an error
agent.acknowledge(ack, message);
// send the fault
agent.fault(createRequestTimeoutErrorMessage(), message);
}
}