[3733] | 1 | <?php |
---|
| 2 | /** |
---|
| 3 | * We support both LOCK and UNLOCK methods in this function |
---|
| 4 | */ |
---|
| 5 | |
---|
| 6 | require_once('XMLDocument.php'); |
---|
| 7 | $reply = new XMLDocument(array( 'DAV:' => '' )); |
---|
| 8 | |
---|
| 9 | if ( ! $request->AllowedTo('write') ) { |
---|
| 10 | $request->NeedPrivilege( 'write', $request->path ); |
---|
| 11 | } |
---|
| 12 | |
---|
| 13 | if ( ! isset($request->xml_tags) ) { |
---|
| 14 | if ( isset($request->lock_token) ) { |
---|
| 15 | // It's OK for LOCK refresh requests to be empty. |
---|
| 16 | $request->xml_tags = array(); |
---|
| 17 | } |
---|
| 18 | else { |
---|
| 19 | $request->XMLResponse( 400, new XMLElement( 'error', new XMLElement('missing-xml-for-request'), $reply->GetXmlNsArray() ) ); |
---|
| 20 | } |
---|
| 21 | } |
---|
| 22 | |
---|
| 23 | |
---|
| 24 | $unsupported = array(); |
---|
| 25 | $lockinfo = array(); |
---|
| 26 | $inside = array(); |
---|
| 27 | |
---|
| 28 | foreach( $request->xml_tags AS $k => $v ) { |
---|
| 29 | |
---|
| 30 | $tag = $v['tag']; |
---|
| 31 | dbg_error_log( "LOCK", " Handling Tag '%s' => '%s' ", $k, $v ); |
---|
| 32 | switch ( $tag ) { |
---|
| 33 | case 'DAV::lockinfo': |
---|
| 34 | dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag ); |
---|
| 35 | if ( $v['type'] == "open" ) { |
---|
| 36 | $lockscope = ""; |
---|
| 37 | $locktype = ""; |
---|
| 38 | $lockowner = ""; |
---|
| 39 | $inside[$tag] = true; |
---|
| 40 | } |
---|
| 41 | else if ( $inside[$tag] && $v['type'] == "close" ) { |
---|
| 42 | $lockinfo['scope'] = $lockscope; unset($lockscope); |
---|
| 43 | $lockinfo['type'] = $locktype; unset($locktype); |
---|
| 44 | $lockinfo['owner'] = $lockowner; unset($lockowner); |
---|
| 45 | $inside[$tag] = false; |
---|
| 46 | } |
---|
| 47 | break; |
---|
| 48 | |
---|
| 49 | case 'DAV::owner': |
---|
| 50 | case 'DAV::locktype': |
---|
| 51 | case 'DAV::lockscope': |
---|
| 52 | dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag ); |
---|
| 53 | if ( $inside['DAV::lockinfo'] ) { |
---|
| 54 | if ( $v['type'] == "open" ) { |
---|
| 55 | $inside[$tag] = true; |
---|
| 56 | } |
---|
| 57 | else if ( $inside[$tag] && $v['type'] == "close" ) { |
---|
| 58 | $inside[$tag] = false; |
---|
| 59 | } |
---|
| 60 | } |
---|
| 61 | break; |
---|
| 62 | |
---|
| 63 | /*case 'DAV::SHARED': */ /** Shared lock is not supported yet */ |
---|
| 64 | case 'DAV::exclusive': |
---|
| 65 | dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag ); |
---|
| 66 | if ( $inside['DAV::lockscope'] && $v['type'] == "complete" ) { |
---|
| 67 | $lockscope = strtolower(substr($tag,5)); |
---|
| 68 | } |
---|
| 69 | break; |
---|
| 70 | |
---|
| 71 | /* case 'DAV::READ': */ /** RFC2518 is pretty vague about read locks */ |
---|
| 72 | case 'DAV::write': |
---|
| 73 | dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag ); |
---|
| 74 | if ( $inside['DAV::locktype'] && $v['type'] == "complete" ) { |
---|
| 75 | $locktype = strtolower(substr($tag,5)); |
---|
| 76 | } |
---|
| 77 | break; |
---|
| 78 | |
---|
| 79 | case 'DAV::href': |
---|
| 80 | dbg_error_log( "LOCK", ":Request: %s -> %s", $v['type'], $tag ); |
---|
| 81 | dbg_log_array( "LOCK", "DAV:href", $v, true ); |
---|
| 82 | if ( $inside['DAV::owner'] && $v['type'] == "complete" ) { |
---|
| 83 | $lockowner = $v['value']; |
---|
| 84 | } |
---|
| 85 | break; |
---|
| 86 | |
---|
| 87 | default: |
---|
| 88 | if ( preg_match('/^(.*):([^:]+)$/', $tag, $matches) ) { |
---|
| 89 | $unsupported[$matches[2]] = $matches[1]; |
---|
| 90 | } |
---|
| 91 | else { |
---|
| 92 | $unsupported[$tag] = ""; |
---|
| 93 | } |
---|
| 94 | dbg_error_log( "LOCK", "Unhandled tag >>%s<<", $tag); |
---|
| 95 | } |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | |
---|
| 99 | |
---|
| 100 | |
---|
| 101 | $request->UnsupportedRequest($unsupported); // Won't return if there was unsupported stuff. |
---|
| 102 | |
---|
| 103 | $lock_opener = $request->FailIfLocked(); |
---|
| 104 | |
---|
| 105 | |
---|
| 106 | if ( $request->method == "LOCK" ) { |
---|
| 107 | dbg_error_log( "LOCK", "Attempting to lock resource '%s'", $request->path); |
---|
| 108 | if ( ($lock_token = $request->IsLocked()) ) { // NOTE Assignment in if() is expected here. |
---|
| 109 | $sql = 'UPDATE locks SET start = current_timestamp WHERE opaquelocktoken = :lock_token'; |
---|
| 110 | $params = array( ':lock_token' => $lock_token); |
---|
| 111 | } |
---|
| 112 | else { |
---|
| 113 | /** |
---|
| 114 | * A fresh lock |
---|
| 115 | */ |
---|
| 116 | $lock_token = uuid(); |
---|
| 117 | $sql = 'INSERT INTO locks ( dav_name, opaquelocktoken, type, scope, depth, owner, timeout, start ) |
---|
| 118 | VALUES( :dav_name, :lock_token, :type, :scope, :request_depth, :owner, :timeout::interval, current_timestamp )'; |
---|
| 119 | $params = array( |
---|
| 120 | ':dav_name' => $request->path, |
---|
| 121 | ':lock_token' => $lock_token, |
---|
| 122 | ':type' => $lockinfo['type'], |
---|
| 123 | ':scope' => $lockinfo['scope'], |
---|
| 124 | ':request_depth' => $request->depth, |
---|
| 125 | ':owner' => $lockinfo['owner'], |
---|
| 126 | ':timeout' => $request->timeout.' seconds' |
---|
| 127 | ); |
---|
| 128 | header( "Lock-Token: <opaquelocktoken:$lock_token>" ); |
---|
| 129 | } |
---|
| 130 | $qry = new AwlQuery($sql, $params ); |
---|
| 131 | $qry->Exec("LOCK",__LINE__,__FILE__); |
---|
| 132 | |
---|
| 133 | $lock_row = $request->GetLockRow($lock_token); |
---|
| 134 | $activelock = array( |
---|
| 135 | new XMLElement( 'locktype', new XMLElement( $lock_row->type )), |
---|
| 136 | new XMLElement( 'lockscope', new XMLElement( $lock_row->scope )), |
---|
| 137 | new XMLElement( 'depth', $request->GetDepthName() ), |
---|
| 138 | new XMLElement( 'owner', new XMLElement( 'href', $lock_row->owner )), |
---|
| 139 | new XMLElement( 'timeout', 'Second-'.$request->timeout), |
---|
| 140 | new XMLElement( 'locktoken', new XMLElement( 'href', 'opaquelocktoken:'.$lock_token )) |
---|
| 141 | ); |
---|
| 142 | $response = new XMLElement("lockdiscovery", new XMLElement( "activelock", $activelock), array("xmlns" => "DAV:") ); |
---|
| 143 | } |
---|
| 144 | elseif ( $request->method == "UNLOCK" ) { |
---|
| 145 | /** |
---|
| 146 | * @TODO: respond with preconditionfailed(409,'lock-token-matches-request-uri') if |
---|
| 147 | * there is no lock to be deleted. |
---|
| 148 | */ |
---|
| 149 | dbg_error_log( "LOCK", "Attempting to unlock resource '%s'", $request->path); |
---|
| 150 | if ( ($lock_token = $request->IsLocked()) ) { // NOTE Assignment in if() is expected here. |
---|
| 151 | $sql = 'DELETE FROM locks WHERE opaquelocktoken = :lock_token'; |
---|
| 152 | $qry = new AwlQuery($sql, array( ':lock_token' => $lock_token) ); |
---|
| 153 | $qry->Exec("LOCK",__LINE__,__FILE__); |
---|
| 154 | } |
---|
| 155 | $request->DoResponse( 204 ); |
---|
| 156 | } |
---|
| 157 | |
---|
| 158 | |
---|
| 159 | $prop = new XMLElement( "prop", $response, array('xmlns'=>'DAV:') ); |
---|
| 160 | // dbg_log_array( "LOCK", "XML", $response, true ); |
---|
| 161 | $xmldoc = $prop->Render(0,'<?xml version="1.0" encoding="utf-8" ?>'); |
---|
| 162 | $request->DoResponse( 200, $xmldoc, 'text/xml; charset="utf-8"' ); |
---|
| 163 | |
---|