blob: a7d85ec0be92d42b591228bd8da02a7f859668d1 [file]
//
// HTTPServerController.m
// iWebDriver
//
// Copyright 2009 Google Inc.
// Copyright 2011 Software Freedom Conservancy.
//
// Licensed 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.
#import "HTTPServerController.h"
#import "HTTPServer.h"
#import "WebDriverHTTPConnection.h"
#import "RESTServiceMapping.h"
#import "WebDriverPreferences.h"
#import "Status.h"
#import "NSObject+SBJson.h"
#import <sys/types.h>
#import <sys/socket.h>
#import <ifaddrs.h>
#import <arpa/inet.h>
@implementation HTTPServerController
@synthesize status = status_;
@synthesize viewController = viewController_;
@synthesize serviceMapping = serviceMapping_;
static NSMutableData *webData;
-(NSString *)getAddress {
struct ifaddrs *head;
if (getifaddrs(&head))
return @"unknown";
// Default to return localhost.
NSString *address = @"127.0.0.1";
// |head| contains the first element in a linked list of interface addresses.
// Iterate through the list.
for (struct ifaddrs *ifaddr = head;
ifaddr != NULL;
ifaddr = ifaddr->ifa_next) {
struct sockaddr *sock = ifaddr->ifa_addr;
NSString *interfaceName = [NSString stringWithUTF8String:ifaddr->ifa_name];
// Ignore localhost.
if ([interfaceName isEqualToString:@"lo0"])
continue;
// Ignore IPv6 for now.
if (sock->sa_family == AF_INET) {
struct in_addr inaddr = ((struct sockaddr_in *)sock)->sin_addr;
char *name = inet_ntoa(inaddr);
address = [NSString stringWithUTF8String:name];
// if wifi use this, otherwise it's the carrier network (pdp_ip0)
// keep looking for the wifi, if no other network interface is found
// it will use the carrier network.
if ([interfaceName isEqualToString:@"en0"]) {
break;
}
}
}
freeifaddrs(head);
return address;
}
-(id) init {
if (![super init])
return nil;
UInt16 portNumber = [[WebDriverPreferences sharedInstance] serverPortNumber];
NSString* grid = [[WebDriverPreferences sharedInstance] gridLocation];
server_ = [[HTTPServer alloc] init];
[server_ setType:@"_http._tcp."];
[server_ setPort:portNumber];
[server_ setConnectionClass:[WebDriverHTTPConnection class]];
NSError *error;
BOOL success = [server_ start:&error];
if(!success) {
NSLog(@"Error starting HTTP Server: %@", error);
}
NSLog(@"HTTP server started on addr %@ port %d",
[self getAddress],
[server_ port]);
status_ = [[NSString alloc] initWithFormat:@"Started at http://%@:%d/wd/hub/",
[self getAddress],
[server_ port]];
if([grid length] > 0) {
NSString* gridPort = [[WebDriverPreferences sharedInstance] gridPort];
NSString *registerUrlStr = [NSString stringWithFormat:@"http://%@:%@/grid/register", grid, gridPort];
NSNumber *num = [NSNumber numberWithInt:1];
// just want "iPad" or "iPhone"
NSString *device = [[[[UIDevice currentDevice] model] componentsSeparatedByString:@" "] objectAtIndex:0];
NSDictionary *capabilitiesDict = [NSDictionary dictionaryWithObjectsAndKeys:
@"WebDriver", @"seleniumProtocol",
device, @"browserName",
num, @"maxInstances",
@"MAC", @"platform", // TODO change from MAC to iOS
nil];
NSDictionary *configurationDict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:[server_ port]], @"port",
[NSNumber numberWithBool:true], @"register",
[self getAddress], @"host",
@"org.openqa.grid.selenium.proxy.DefaultRemoteProxy", @"proxy",
num, @"maxSession",
grid, @"hubHost",
gridPort, @"hubPort",
@"wd", @"role",
[NSNumber numberWithInt:5000], @"registerCycle",
registerUrlStr, @"hub",
[NSString stringWithFormat:@"http://%@:%d", [self getAddress], [server_ port] ], @"remoteHost",
nil];
NSDictionary *gridRegistrationData = [NSDictionary dictionaryWithObjectsAndKeys:
@"org.openqa.grid.common.RegistrationRequest", @"class",
[NSArray arrayWithObject:capabilitiesDict], @"capabilities",
configurationDict, @"configuration",
nil];
NSURL *registerUrl = [NSURL URLWithString:registerUrlStr];
NSMutableURLRequest *gridRegister = [NSMutableURLRequest requestWithURL:registerUrl];
NSString *json = [gridRegistrationData JSONRepresentation];
NSString *msgLength = [NSString stringWithFormat:@"%d", [json length]];
[gridRegister addValue: msgLength forHTTPHeaderField:@"Content-Length"];
[gridRegister setHTTPMethod:@"POST"];
[gridRegister setHTTPBody: [json dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:gridRegister delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
webData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
status_ = [NSString stringWithFormat:@"Couldn't connect to grid at %@", registerUrlStr];
}
}
serviceMapping_ = [[RESTServiceMapping alloc] initWithIpAddress:[self getAddress]
port:[server_ port]];
return self;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"ERROR with theConenction");
[connection release];
[webData release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"DONE. Received Bytes: %d", [webData length]);
NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes]
length:[webData length]
encoding:NSUTF8StringEncoding];
NSLog(@"%@",theXML);
[theXML release];
}
// Singleton
static HTTPServerController *singleton = nil;
+(HTTPServerController*) sharedInstance {
if (singleton == nil) {
singleton = [[HTTPServerController alloc] init];
}
return singleton;
}
- (NSObject<HTTPResponse> *)httpResponseForRequest:(HTTPMessage*)request {
return [serviceMapping_ httpResponseForRequest:request];
}
- (NSObject *)httpResponseForQuery:(NSString *)query
method:(NSString *)method
withData:(NSData *)theData {
return [serviceMapping_.serverRoot httpResponseForQuery:query
method:method
withData:theData];
}
@end