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 | |
---|