diff --git services.info services.info
index d1ac495..82e5b49 100644
--- services.info
+++ services.info
@@ -15,6 +15,7 @@ files[] = services.servers.api.php
 files[] = serviers.services.api.php
 files[] = tests/functional/NoAuthEndpointTestRunner.test
 files[] = tests/functional/ServicesResourceNodeTests.test
+files[] = tests/functional/ServicesResourceUserTests.test
 files[] = tests/functional/ServicesEndpointTests.test
 files[] = tests/unit/TestServicesModule.test
 dependencies[] = ctools
\ No newline at end of file
diff --git tests/functional/ServicesResourceNodeTests.test tests/functional/ServicesResourceNodeTests.test
index b261c93..e2d10e2 100644
--- tests/functional/ServicesResourceNodeTests.test
+++ tests/functional/ServicesResourceNodeTests.test
@@ -1,300 +1,246 @@
 <?php
+// $Id: ServicesResourceNodeTests.test,v 1.1.2.3 2011/01/19 00:25:40 ocyrus Exp $
+
 /**
  * @file
  * Call the endpoint tests when no authentication is being used.
  *
  */
+
 require_once('ServicesWebTestCase.php') ;
 
 /**
  * Run test cases for the endpoint with no authentication turned on.
  *
  */
- class ServicesResourceNodeTests extends ServicesWebTestCase {
+class ServicesResourceNodetests extends ServicesWebTestCase {
+  // Class variables
   protected $privilegedUser = NULL ;
-	/**
-    * Implementation of setUp().
-    */
-   public function setUp() {
-     parent::setUp(
-     	'ctools',
-     	'services',
-      'rest_server',
-      'services_sessauth',
-      'inputstream'
-     );
-   }
-   public static function getInfo() {
-     return array(
-       'name'        => t('Resource Node tests, no auth'),
-       'description' =>
-         t('Test the resource NODE methods and actions.'),
-       'group'       => t('Services'),
-     );
+  // Endpoint details.
+  protected $endpoint = NULL;
+
+  /**
+   * Implementation of setUp().
+   */
+  public function setUp() {
+    parent::setUp(
+      'ctools',
+      'services',
+      'rest_server'
+    );
+    // Set up endpoint.
+    $this->endpoint =  $this->saveNewEndpoint();
+  }
+
+  /**
+   * Implementation of getInfo().
+   */
+  public static function getInfo() {
+   return array(
+     'name'        => t('Resource Node'),
+     'description' => t('test the resource Node methods and actions.'),
+     'group'       => t('Services'),
+   );
   }
 
-   /**
-    * testing node_resource Index
-    */
-   public function testNewEndpointResourceNodeIndex() {
+  /**
+   * testing node_resource Index
+   */
+  public function testNewEndpointResourceNodeIndex() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
+      'administer services',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+
     $node = $this->drupalCreateNode();
-    $responseArray = $this->servicesGet($endpoint->path.'/node');
-    $nodeResourceIndex = json_decode($responseArray['body']);
-    if($node->title == $nodeResourceIndex[0]->title) {
-      $this->pass('Successfully received Node info', 'NodeResource: Index');
-    } else {
-      $this->fail(t('Something went wrong. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Index');
-    }
-   }
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node');
+    $this->assertTrue($node->title == $responseArray['body'][0]->title, t('Successfully received Node info'), 'NodeResource: Index');
+  }
+
   /**
-    * testing node_resource Get
-    */
-   public function testNewEndpointResourceNodeGet() {
-     // Create and log in our privileged user.
-     $this->privilegedUser = $this->drupalCreateUser(array(
-         'administer services',
-     ));
-     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+   * testing node_resource Get
+   */
+  public function testNewEndpointResourceNodeGet() {
+    // Create and log in our privileged user.
+    $this->privilegedUser = $this->drupalCreateUser(array(
+      'administer services',
+    ));
+    $this->drupalLogin($this->privilegedUser);
     $node = $this->drupalCreateNode();
-    $responseArray = $this->servicesGet($endpoint->path.'/node/'. $node->nid);
-    $nodeResourceGet = json_decode($responseArray['body']);
-    if($node->title == $nodeResourceGet->title) {
-      $this->pass('Successfully received Node info', 'NodeResource: Retrieve');
-    } else {
-      $this->fail(t('Something went wrong. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Retrieve');
-    }
-    //Verify node not Found
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node/' . $node->nid);
+    $this->assertTrue($node->title == $responseArray['body']->title, t('Successfully received Node info'), 'NodeResource: Retrieve');
+    //Verify node not found.
     unset($node);
-    $responseArray = $this->servicesGet($endpoint->path.'/node/99');
-    if($responseArray['code'] == '404') {
-      $this->pass('Successfully was rejected to non existent node', 'NodeResource: Retrieve');
-    } else {
-      $this->pass('I didnt get rejected, bad news!', 'NodeResource: Retrieve');
-    }
-   }
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node/99');
+    $this->assertTrue($responseArray['code'] == '404', t('Successfully was rejected to non existent node'), 'NodeResource: Retrieve');
+  }
+
   /**
-    * testing node_resource Create
-    */
-   public function testEndpointResourceNodeCreate() {
+   * testing node_resource Create
+   */
+  public function testEndpointResourceNodeCreate() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer content types',
-       'create article content',
+      'administer services',
+      'bypass node access',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = array(
-      'node[title]' => 'testing',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[type]' => 'article',
-      'node[language]' => 'UND',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => 'testing',
+      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomString()))),
+      'type' => 'page',
+      'name' => $this->privilegedUser->name,
+      'language' => LANGUAGE_NONE,
     );
-    
-    $data = $this->services_build_postfields($node);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceCreateReturn = json_decode($responseArray['body']);
-    
-    if(isset($nodeResourceCreateReturn->nid)) {
-      $this->pass('Node was successfully created',  'NodeResource: Create');
-      $newNode = node_load($nodeResourceCreateReturn->nid);
-      if($newNode->title = $node['node[title]']) {
-        $this->pass('Title was the same',  'NodeResource: Create');
-      } else {
-        $this->fail('Title was different', 'NodeResource: Create');
-      }
-      if($newNode->body = $node['node[body][UND][0][value]']) {
-        $this->pass('Body was the same', 'NodeResource: Create');
-      } else {
-        $this->fail('Body was different', 'NodeResource: Create');
-      }
-    } else {
-      $this->fail(t('Creating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Create');
-    }
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+    $nodeResourceCreateReturn = $responseArray['body'];
+
+    $this->assertTrue(isset($nodeResourceCreateReturn['nid']), t('Node was successfully created'), 'NodeResource: Create');
+    $newNode = node_load($nodeResourceCreateReturn['nid']);
+    $this->assertTrue($newNode->title = $node['title'], t('Title was the same'), 'NodeResource: Create');
+    $this->assertTrue($newNode->body = $node['body'], t('Body was the same'), 'NodeResource: Create');
   }
+
   /**
-    * testing node_resource Created make ure it fails with no perms
-    */
-   public function testEndpointResourceNodeCreateFail() {
+   * testing node_resource Created make ure it fails with no perms
+   */
+  public function testEndpointResourceNodeCreateFail() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
+      'administer services',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = array(
-      'node[title]' => 'testing',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[type]' => 'article',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => 'testing',
+      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomString()))),
+      'type' => 'page',
+      'name' => $this->privilegedUser->name,
+      'language' => LANGUAGE_NONE,
     );
-    
-    $data = $this->services_build_postfields($node);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceCreateReturn = json_decode($responseArray['body']);
-    
-    if($responseArray['code'] = 401) {
-      $this->pass('User with permissions cannot create node',  'NodeResource: Create');
-    } else {
-      $this->fail(t('User was able to create nodes without permission. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Create');
-    }
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+
+    $this->assertTrue($responseArray['code'] == 401, t('User with not sufficient permissions cannot create node'), 'NodeResource: Create');
   }
+
   /**
-    * testing node_resource Validate missing Title
-    */
-   public function testEndpointResourceNodeCreateMissingTitle() {
+   * testing node_resource Validate missing Title
+   */
+  public function testEndpointResourceNodeCreateMissingTitle() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer content types',
+      'administer services',
+      'bypass node access',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
-    $node = $this->drupalCreateNode();
-    $node_update = array(
-      'node[title]' => '',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[name]' => $this->privilegedUser->name,
-      'node[type]' => 'article',
+
+    $node = array(
+      'title' => '',
+      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomString()))),
+      'type' => 'page',
+      'name' => $this->privilegedUser->name,
+      'language' => LANGUAGE_NONE,
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(strpos($responseArray['status'], 'Title field is required.')) {
-      $this->pass('Node was not created, no title. ', 'NodeResource: Created');
-    }
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+
+    $nodeResourceUpdateReturn = $responseArray['body'];
+    $this->assertTrue(strpos($responseArray['status'], 'Title field is required.'), t('Node was not created without title.'), 'NodeResource: Create');
   }
+
   /**
-    * testing node_resource Update
-    */
-   public function testEndpointResourceNodeUpdate() {
+  * testing node_resource Update
+  */
+  public function testEndpointResourceNodeUpdate() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer content types',
+      'administer services',
+      'bypass node access',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
-    $node_update = array(
-      'node[title]' => 'testing',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[type]' => 'article',
-      'node[name]' => $this->privilegedUser->name,
-    );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(isset($nodeAfterUpdate->nid)) {
-      $this->pass('Node was successfully updated',  'NodeResource: Updated');
-      if($nodeAfterUpdate->title = $node_update['node[title]']) {
-        $this->pass('Title was the same',  'NodeResource: Update');
-      } else {
-        $this->fail('Title was different', 'NodeResource: Update');
-      }
-      if($nodeAfterUpdate->body = $node_update['node[body]']) {
-        $this->pass('Body was the same', 'NodeResource: Update');
-      } else {
-        $this->fail('Body was different', 'NodeResource: Update');
-      }
-    } else {
-      $this->fail(t('Updating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Update');
-    }
+
+    $node_update = clone $node;
+    $node_update->title = $this->randomName();
+    $node_update->body[LANGUAGE_NONE][0]['value'] = $this->randomName();
+
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+    // Load node not from cache.
+    $nodeAfterUpdate = node_load($responseArray['body'], NULL, TRUE);
+    $this->assertTrue(isset($nodeAfterUpdate->nid), t('Node was successfully updated'), 'NodeResource: Updated');
+    $this->assertEqual($nodeAfterUpdate->title, $node_update->title, t('Title is the same'), 'NodeResource: Update');
+    $this->assertEqual($nodeAfterUpdate->body[LANGUAGE_NONE][0]['value'], $node_update->body[LANGUAGE_NONE][0]['value'], t('Body is the same'), 'NodeResource: Update');
   }
+
   /**
-    * testing node_resource Update fail with no permissions
-    */
-   public function testEndpointResourceNodeUpdatePermFail() {
+  * testing node_resource Update fail with no permissions
+  */
+  public function testEndpointResourceNodeUpdatePermFail() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'create article content',
-       'edit own article content',
+      'administer services',
+      'create page content',
+      'edit own page content',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+
+    // Create node from user no 1.
     $node = $this->drupalCreateNode(array('uid' => 1));
-    $node_update = array(
-      'node[title]' => 'testing',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[type]' => 'article',
-    );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(isset($nodeAfterUpdate->nid)) {
-      $this->fail(t('Updating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Update');
-    } else {
-      $this->pass(t('Updating the node failed. This is good!'), 'NodeResource: Update');
-    }
+
+    // Try to update this node with different user not
+    // having permission to edit any story content.
+    $node_update = clone $node;
+    $node_update->title = $this->randomName();
+    $node_update->body[LANGUAGE_NONE][0]['value'] = $this->randomName();
+
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+
+    $this->assertTrue(strpos($responseArray['status'], 'Access denied for user'), t('Updating the node failed without needed permissions. This is good!'), 'NodeResource: Update');
   }
+
   /**
-    * testing node_resource Update verify missing title
-    */
-   public function testEndpointResourceNodeUpdateMissingTitle() {
+   * testing node_resource Update verify missing title
+   */
+  public function testEndpointResourceNodeUpdateMissingTitle() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer content types',
+      'administer services',
+      'bypass node access',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
     $node_update = array(
-      'node[title]' => '',
-      'node[body][UND][0][value]' => 'bodytest',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => '',
+      'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomString()))),
+      'name' => $this->privilegedUser->name,
+      'type' => 'page',
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(strpos($responseArray['status'], 'Title field is required.')) {
-      $this->pass('Node was not created, no title. ', 'NodeResource: Update');
-    }
+
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+    $this->assertTrue(strpos($responseArray['status'], 'Title field is required.'), t('Node was not updated without title.'), 'NodeResource: Update');
   }
+
   /**
-    * testing node_resource Delete
-    */
-   public function testEndpointResourceNodeDelete() {
+   * testing node_resource Delete
+   */
+  public function testEndpointResourceNodeDelete() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer content types',
-       'access content',
+      'administer services',
+      'bypass node access',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
     $data = '';
-    $responseArray = $this->servicesDelete($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    if($responseArray['code'] == 200) {
-      $this->pass('Node was deleted.', 'NodeResource: Deleted');
-    } else {
-      $this->fail(t('Deleting the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Delete');
-    }
-    $responseArray = $this->servicesDelete($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    if($responseArray['code'] == 200) {
-      $this->fail('Node was deleted. It shoudlnt have been because it doesnt exist', 'NodeResource: Deleted');
-    } else {
-      $this->pass(t('Was not abled to delete node because it doesnt exist. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Delete');
-    }
+
+    $responseArray = $this->servicesDelete($this->endpoint->path . '/node/' . $node->nid, $data);
+    $deleted_node = node_load($node->nid, NULL, TRUE);
+    $this->assertTrue(empty($deleted_node), t('Node was deleted.'), 'NodeResource: Deleted');
+
+    $responseArray = $this->servicesDelete($this->endpoint->path . '/node/' . $node->nid, $data);
+
+    $this->assertFalse($responseArray['code'] == 200, t('Node was deleted. It shoudlnt have been because it doesnt exist'), 'NodeResource: Deleted');
   }
 }
diff --git tests/functional/ServicesWebTestCase.php tests/functional/ServicesWebTestCase.php
index 9c24087..30523a9 100644
--- tests/functional/ServicesWebTestCase.php
+++ tests/functional/ServicesWebTestCase.php
@@ -1,95 +1,158 @@
 <?php
- class ServicesWebTestCase extends DrupalWebTestCase {
-  protected function servicesGet($url, $data = NULL, $parameters = NULL) {
-    $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($url, $options), CURLOPT_NOBODY => FALSE, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HEADER => TRUE, CURLOPT_HTTPHEADER => array("Accept: application/json")));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
+// $Id: ServicesWebTestCase.php,v 1.1.2.4 2011/01/19 00:25:40 ocyrus Exp $
+
+class ServicesWebTestCase extends DrupalWebTestCase {
+
+  protected function servicesGet($url, $data = NULL, $headers = array()) {
+    $options = array('query' => $data);
+    $url = url($this->getAbsoluteUrl($url) . '.php', $options);
+    $headers = array();
+    $content = $this->curlExec(array(
+      CURLOPT_HTTPGET => TRUE,
+      CURLOPT_URL => $url,
+      CURLOPT_NOBODY => FALSE,
+      CURLOPT_RETURNTRANSFER => TRUE,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_HTTPHEADER => $headers
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
     $this->verbose('GET request to: ' . $url .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
-  protected function servicesPost($url, $data = NULL, $headers = array()) {
+
+  protected function servicesPost($url, $data = array(), $headers = array()) {
     $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_URL => $url, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $data, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => TRUE));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
+    // Add .php to get serialized response.
+    $url = $this->getAbsoluteUrl($url) . '.php';
+
+    // Otherwise Services will reject arguments.
+    $headers = array("Content-type: application/x-www-form-urlencoded");
+    // Prepare arguments.
+    $post = http_build_query($data, '', '&');
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_POST => TRUE,
+      CURLOPT_POSTFIELDS => $post,
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_RETURNTRANSFER => TRUE
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
     $this->verbose('POST request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
+
   protected function servicesPut($url, $data = NULL, $headers = array()) {
     $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $putData = tmpfile();
-    // Write the string to the temporary file
-    fwrite($putData, $data);
+    $url = $this->getAbsoluteUrl($url) . '.php';
+
+    $serialize_args = serialize($data);
+
+    // Set up headers so arguments will be unserialized.
+    $headers = array("Content-type: application/vnd.php.serialized; charset=iso-8859-1");
+
+    // Emulate file.
+    $putData = fopen('php://memory', 'rw+');
+    fwrite($putData, $serialize_args);
     fseek($putData, 0);
-    $content = $this->curlExec(array(CURLOPT_URL => $url,CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_POSTFIELDS => $data, CURLOPT_HTTPHEADER => $headers, CURLOPT_INFILE =>$putData, CURLOPT_INFILESIZE => strlen($data)));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
-    $this->verbose('PUT request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_RETURNTRANSFER => TRUE,
+      CURLOPT_PUT => TRUE,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_INFILE => $putData,
+      CURLOPT_INFILESIZE => strlen($serialize_args)
+    ));
     fclose($putData);
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
+    $this->verbose('PUT request to: ' . $url .
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
+
   protected function servicesDelete($url, $data = NULL, $headers = array()) {
-    $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => "DELETE", CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => TRUE));
+    $options = array('query' => $data);
+    $url = url($this->getAbsoluteUrl($url) . '.php', $options);
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_CUSTOMREQUEST => "DELETE",
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_RETURNTRANSFER => TRUE
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
+    $this->verbose('DELETE request to: ' . $url .
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
+    return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
+  }
+
+  /*
+  ------------------------------------
+  HELPER METHODS
+  ------------------------------------
+  */
+
+  /**
+   * Parse header.
+   *
+   * @param type $content
+   * @return type
+   */
+  function parseHeader($content) {
     $info = curl_getinfo($this->curlHandle);
     $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
+    $header = str_replace("HTTP/1.1 100 Continue\r\n\r\n", '', $header);
+    $status = strtok($header, "\r\n");
     $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
-    $this->verbose('DELETE request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
-    return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
+    $body = unserialize(substr($content, $info['header_size'], strlen($content) - $info['header_size']));
+    return array($info, $header, $status, $code, $body);
   }
 
-   /*
-    ------------------------------------
-    HELPER METHODS
-    ------------------------------------
+  /**
+   * Creates a data array for populating an endpoint creation form.
+   *
+   * @return
+   * An array of fields for fully populating an endpoint creation form.
    */
+  public function populateEndpointFAPI() {
+    return array(
+      'name'   => 'machinename',
+      'title'  => $this->randomName(20),
+      'path'   => $this->randomName(10),
+      'server' => 'rest_server',
+      'services_use_content_permissions' => TRUE,
+    );
+  }
 
-   /**
-    * Creates a data array for populating an endpoint creation form.
-    *
-    * @return
-    * An array of fields for fully populating an endpoint creation form.
-    */
-   public function populateEndpointFAPI() {
-     return array(
-       'name'   => 'mchnname',
-       'title'  => $this->randomName(20),
-       'path'   => $this->randomName(10),
-       'server' => 'rest_server',
-     );
-   }
-   public function saveNewEndpoint() {
+  public function saveNewEndpoint() {
     $edit = $this->populateEndpointFAPI() ;
     $endpoint = new stdClass;
     $endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
@@ -98,9 +161,7 @@
     $endpoint->title = $edit['title'];
     $endpoint->server = $edit['server'];
     $endpoint->path = $edit['path'];
-    $endpoint->authentication = array(
-      'services_sessauth' => array(),
-    );
+    $endpoint->authentication = array();
     $endpoint->resources = array(
       'node' => array(
         'alias' => '',
@@ -268,39 +329,95 @@
     $endpoint->status = 1;
     services_endpoint_save($endpoint);
     $endpoint = services_endpoint_load($endpoint->name);
-    if($endpoint->name == $edit['name']) {
-      $this->pass('Endpoint successfully created');  
-    } else {
-       $this->fail('Endpoint creation failed');  
+    $this->assertTrue($endpoint->name == $edit['name'], t('Endpoint successfully created'));
+    return $endpoint;
+  }
+
+  /**
+   * Performs a cURL exec with the specified options after calling curlConnect().
+   *
+   * @param $curl_options
+   *   Custom cURL options.
+   * @return
+   *   Content returned from the exec.
+   */
+  protected function curlExec($curl_options, $redirect = FALSE) {
+    $this->curlInitialize();
+
+    // cURL incorrectly handles URLs with a fragment by including the
+    // fragment in the request to the server, causing some web servers
+    // to reject the request citing "400 - Bad Request". To prevent
+    // this, we strip the fragment from the request.
+    // TODO: Remove this for Drupal 8, since fixed in curl 7.20.0.
+    if (!empty($curl_options[CURLOPT_URL]) && strpos($curl_options[CURLOPT_URL], '#')) {
+      $original_url = $curl_options[CURLOPT_URL];
+      $curl_options[CURLOPT_URL] = strtok($curl_options[CURLOPT_URL], '#');
     }
-     $this->servicesGet($endpoint->path);
-     return $endpoint;
-   }
- /**
- * Builds out our post fields
- *
- */
-  public function services_build_postfields($data = array()) {
-    $post_data = '';  
-    if (is_array($data) && !empty($data)) {
-      array_walk($data, array($this, 'services_flatten_fields'));
-      $post_data = implode('&', $data);
+
+    $url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
+
+    if (!empty($curl_options[CURLOPT_POST])) {
+      // This is a fix for the Curl library to prevent Expect: 100-continue
+      // headers in POST requests, that may cause unexpected HTTP response
+      // codes from some webservers (like lighttpd that returns a 417 error
+      // code). It is done by setting an empty "Expect" header field that is
+      // not overwritten by Curl.
+      $curl_options[CURLOPT_HTTPHEADER][] = 'Expect:';
     }
-    if(is_object($data) && !empty($data)) {
-      array_walk(get_object_vars($data), array($this, 'services_flatten_fields'));
-      $post_data = implode('&', $data);
+    curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
+
+    if (!$redirect) {
+      // Reset headers, the session ID and the redirect counter.
+      $this->session_id = NULL;
+      $this->headers = array();
+      $this->redirect_count = 0;
+    }
+
+    $content = curl_exec($this->curlHandle);
+    $status = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+
+    // cURL incorrectly handles URLs with fragments, so instead of
+    // letting cURL handle redirects we take of them ourselves to
+    // to prevent fragments being sent to the web server as part
+    // of the request.
+    // TODO: Remove this for Drupal 8, since fixed in curl 7.20.0.
+    if (in_array($status, array(300, 301, 302, 303, 305, 307)) && $this->redirect_count < variable_get('simpletest_maximum_redirects', 5)) {
+      if ($this->drupalGetHeader('location')) {
+        $this->redirect_count++;
+        $curl_options = array();
+        $curl_options[CURLOPT_URL] = $this->drupalGetHeader('location');
+        $curl_options[CURLOPT_HTTPGET] = TRUE;
+        return $this->curlExec($curl_options, TRUE);
+      }
+    }
+
+    $this->drupalSetContent($content, isset($original_url) ? $original_url : curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
+
+    // Analyze the method for log message.
+    $method = '';
+    if (!empty($curl_options[CURLOPT_NOBODY])) {
+      $method = 'HEAD';
+    }
+
+    if (empty($method) && !empty($curl_options[CURLOPT_PUT])) {
+      $method = 'PUT';
+    }
+
+    if (empty($method) && !empty($curl_options[CURLOPT_CUSTOMREQUEST])) {
+      $method = $curl_options[CURLOPT_CUSTOMREQUEST];
     }
-    return $post_data;
-  }
-/**
- * Modifies our array data so we can turn it into a querystring
- * 
- * @param string $item - array value
- * @param string $key  - key of the array element
- */
-  public function services_flatten_fields(&$item, $key) {
-    $item = $key .'='. $item;
-  }
 
+    if (empty($method)) {
+      $method = empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST';
+    }
+    $message_vars = array(
+      '!method' => $method,
+      '@url' => isset($original_url) ? $original_url : $url,
+      '@status' => $status,
+      '!length' => format_size(strlen($this->drupalGetContent()))
+    );
+    $message = t('!method @url returned @status (!length).', $message_vars);
+    $this->assertTrue($this->drupalGetContent() !== FALSE, $message, t('Browser'));
+    return $this->drupalGetContent();
+  }
 }
-?>
\ No newline at end of file
