commit(); $db = null; function allow_methods($methods) { global $method; if(is_string($methods)) { if($method == $methods) { return; } header("HTTP/1.1 405 Invalid method"); header("Allow: " . $methods); exit(0); } } function unsupported_media_type() { header("HTTP/1.1 415 Unsupported Media Type"); exit(0); } function conflict($short) { header("HTTP/1.1 409 " . $short); exit(0); } function not_found($short = NULL, $long = NULL) { if(!isset($short)) { $short = "Not found"; } header("HTTP/1.1 404 " . $short); if(isset($long)) { echo($long); } exit(0); } function bad_request($short = NULL, $long = NULL) { if(!isset($short)) { $short = "Bad Request"; } header("HTTP/1.1 400 " . $short); if(isset($long)) { echo($long); } exit(0); } function conneg() { $accept = isset($_SERVER["HTTP_ACCEPT"]) ? $_SERVER["HTTP_ACCEPT"] : NULL; // First media type $accept = preg_replace('/^([^,]*),.*/', '$1', $accept); // var_dump($accept); // Remove parameters $accept = preg_replace('/^([^;]*);.*/', '$1', $accept); // var_dump($accept); return $accept; } function cron() { global $db; allow_methods("POST"); $queues = $db->select_queues(); foreach($queues as $queue) { if(!isset($queue->endpoint_url)) { echo("No endpoint configured for queue " . $queue->name . "\n"); continue; } $items = $db->select_items($queue->name, 1, 0); $count = count($items); if($count > 0) { $item = $items[0]; process_item($queue, $items[0]); break; } echo("Queue " . $queue->name . " is empty.\n"); } } function process_item($queue, $item) { echo("Processing item " . $item->id . " from queue " . $queue->name . "\n"); $input_path = data_file($item->id); $input_fd = fopen($input_path, "r"); $log_path = log_file($item->id); $log_fd = fopen($log_path, "w"); if(!$input_fd || !$log_fd) { echo("Error opening " . $path . "\n"); fclose($input_fd); fclose($log_fd); return; } $handle = curl_init(); // http://no2.php.net/manual/en/function.curl-setopt.php // Set referer on redirecet curl_setopt($handle, CURLOPT_AUTOREFERER, TRUE); // Follow redirects curl_setopt($handle, CURLOPT_FOLLOWLOCATION, TRUE); // We're doing POSTs only. curl_setopt($handle, CURLOPT_POST, TRUE); curl_setopt($handle, CURLOPT_UPLOAD, TRUE); curl_setopt($handle, CURLOPT_MAXREDIRS, 10); curl_setopt($handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); // This should be 2 in production curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 1); // Return the transfer as a string of the return value of curl_exec() // curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); // In seconds curl_setopt($handle, CURLOPT_TIMEOUT, 30); curl_setopt($handle, CURLOPT_URL, $queue->endpoint_url); curl_setopt($handle, CURLOPT_HTTPHEADER, $item->headers); curl_setopt($handle, CURLOPT_INFILE, $input_fd); curl_setopt($handle, CURLOPT_WRITEHEADER, $log_fd); curl_setopt($handle, CURLOPT_FILE, $log_fd); curl_setopt($handle, CURLOPT_STDERR, $log_fd); curl_setopt($handle, CURLOPT_CUSTOMREQUEST, "POST"); echo("Executing request...\n"); fwrite($log_fd, "POST " . $queue->endpoint_url . "\n"); $ret = curl_exec($handle); if($ret === false) { echo("curl failed\n"); echo("error: " . curl_error($handle) . "\n"); } else { echo("curl success\n"); } fclose($input_fd); fclose($log_fd); curl_close($handle); } function enqueue($url_generator, $queue) { global $db; $id = uniqid(); $tmp_file = tmp_file($id); $data_file = data_file($id); try { $stdin = fopen('php://input', 'r'); file_put_contents($tmp_file, $stdin); link($tmp_file, $data_file); unlink($tmp_file); $headers = array(); foreach($_SERVER as $key => $value) { if(strpos($key, "HTTP_") === 0) $headers[strtolower(str_replace('_', '-', substr($key, 5)))] = $value; } $headers["content-type"] = $_SERVER["CONTENT_TYPE"]; $headers["content-length"] = $_SERVER["CONTENT_LENGTH"]; var_dump($headers); $db->insert_item($id, $headers, array($queue)); header("HTTP/1.1 201 Created as " . $id); header("Location: " . $url_generator->item($queue, $id)); } catch (Exception $e) { header("HTTP/1.1 500 Error"); echo("Caught exception: " . $e->getMessage() . "\n"); } } function item($url_generator, $queue, $item) { global $db, $method; list($x, $queue, $id) = $segments; $item = $db->select_item($queue, $id); if($item == NULL) { not_found("No such item: " . $id); } switch($method) { case "GET": header("Link: <" . $url_generator->item_enclosure($item->id) . ">;rel=enclosure"); echo("Showing: " . $item->id . "\n"); echo($item->toPlainText($url_generator)); break; case "DELETE": $db->delete_item($queue, $id); @unlink(data_file($id)); @unlink(log_file($id)); header("HTTP/1.1 204 Deleted item " . $id); break; default: allow_methods("GET", "DELETE"); break; } } function items($url_generator, $queue) { global $db; allow_methods("GET"); header("HTTP/1.1 200 Items in $queue"); $items = $db->select_items($queue); switch(conneg()) { default: case "text/plain": header("Content-Type: text/plain"); template_item_list_text($url_generator, $queue, $items); break; case "text/html": header("Content-Type: text/html"); template_item_list_html($url_generator, $queue, $items); break; } } function queues($url_generator) { global $method, $content_type, $db; switch($method) { case "GET": case "HEAD": $queues = $db->select_queues(); $count = count($queues); switch(conneg()) { default: case "text/plain": header("Content-Type: text/plain"); template_queue_list_text($url_generator, $queues); break; case "text/html": header("Content-Type: text/html"); template_queue_list_html($url_generator, $queues); break; } break; case "POST": $name = NULL; $endpoint_url = NULL; switch($content_type) { case "application/x-www-form-urlencoded": $name = uniqid(); $endpoint_url = $_POST["endpoint_url"]; $db->insert_queue($name, $endpoint_url); header("HTTP/1.1 201 Queue created as " . $name); header("Location: " . $url_generator->queue($name)); break; default: unsupported_media_type(); } break; default: allow_methods("GET", "HEAD", "POST"); } } function queue($url_generator, $queue) { global $method, $content_type, $form, $db; if(!Queue::valid_name($queue)) { not_found("Invalid queue name"); } switch($method) { case "GET": case "HEAD": $q = $db->select_queue($queue); if(!isset($q)) { not_found("No such queue: " . $queue); } switch(conneg()) { case "text/html"; header("Content-Type: text/html"); template_queue_html($url_generator, $q); break; default: case "text/plain"; header("Content-Type: text/plain"); template_queue_text($url_generator, $q); break; } break; case "PUT": $q = $db->select_queue($queue); if($q != NULL) { conflict("Queue already exist: " . $queue); } switch($content_type) { case "application/x-www-form-urlencoded": $name = $queue; $endpoint_url = $_POST["endpoint_url"]; $db->insert_queue($name, $endpoint_url); header("HTTP/1.1 201 Queue created as " . $name); header("Location: " . $url_generator->queue($name)); break; default: unsupported_media_type(); } break; case "PATCH": $q = $db->select_queue($queue); if($q == NULL) { not_found("No such queue: " . $queue); } switch($content_type) { case "application/x-www-form-urlencoded": var_dump($form); $endpoint_url = $form["endpoint_url"]; if(!isset($endpoint_url)) { header("HTTP/1.1 400 Bad request; missing endpoint_url"); exit(0); } else { $db->update_queue($queue, $endpoint_url); header("HTTP/1.1 204 Queue updated " . $queue); header("Content-Location: " . $url_generator->queue($queue)); } break; default: unsupported_media_type(); } break; case "DELETE": $db->delete_queue_and_items($queue); break; default: allow_methods("GET", "HEAD", "PUT", "PATCH", "DELETE"); } } ?>