1 """
2 A renderer for TAP, both sync and async.
3 """
4
5
6
7
8
9
10
11 import os
12 from cStringIO import StringIO
13
14 from nevow import inevow
15 from nevow import rend
16 from twisted.internet import threads
17
18 from gavo import base
19 from gavo import svcs
20 from gavo import utils
21 from gavo.protocols import tap
22 from gavo.protocols import taprunner
23 from gavo.protocols import uws
24 from gavo.protocols import uwsactions
25 from gavo.svcs import streaming
26 from gavo.web import asyncrender
27 from gavo.web import common
28 from gavo.web import grend
29 from gavo.web import vosi
35
38 """the resource executing sync TAP queries.
39
40 While not really going through UWS, this does create a UWS job and
41 tears it down later so we can re-use all the parsing and parameter
42 interpretation of the TAP job.
43 """
47
75
84
88
95
96 request.setHeader("content-type", str(type))
97
98 if hasattr(request, "accumulator"):
99 writeTable(request)
100 return ""
101 else:
102 return streaming.streamOut(writeTable, request)
103
113
121
122
123
124
125
126 -class TAPRenderer(grend.ServiceBasedPage):
127 """A renderer speaking all of TAP (including sync, async, and VOSI).
128
129 Basically, this just dispatches to the sync and async resources.
130 """
131 name = "tap"
132 urlUse = "base"
133
137
139 """creates a files attribute on request, containing all uploaded
140 files.
141
142 The upload files are removed from args, which is good since we
143 don't want to serialize those in the parameters dictionary.
144
145 This method inspects all upload parameters and converts the
146 referenced arguments to cgi-like files as necessary. Missing
147 uploads will be noticed here, and the request will be rejected.
148
149 Of course, all that hurts if someone manages to upload from REQUEST --
150 but that's their fault then.
151 """
152 request.files = {}
153 for uploadSpec in request.args.get("upload", []):
154 if uploadSpec:
155 for tableName, upload in tap.parseUploadString(uploadSpec):
156 if upload.startswith("param:"):
157 paramName = upload[6:]
158 if paramName not in request.args or not request.args[paramName]:
159 raise base.ReportableError("No parameter for upload"
160 " table %s"%tableName)
161
162 item = request.args.pop(paramName)[0]
163
164 if getattr(item, "file", None) is None:
165 item = _FakeUploadedFile(
166 "unnamed_inline_upload_%s"%paramName, item)
167 request.files[paramName] = item
168
170 """changes request so our TAP 1.1 code keeps working with 1.0 clients.
171
172 This is called once, at the very start of handling stuff.
173 """
174 if "format" in request.args:
175 formatVal = request.args.pop("format")
176 if not "responseformat" in request.args:
177 request.args["responseformat"] = formatVal
178
180 request = inevow.IRequest(ctx)
181 uwsactions.lowercaseProtocolArgs(request.args)
182 self._doTAP10CompatCode(request)
183
184 if not segments[-1]:
185 if len(segments)==1:
186 return self, ()
187 raise svcs.WebRedirect(
188 self.service.getURL("tap")+"/"+"/".join(segments[:-1]))
189
190 try:
191 self.gatherUploadFiles(request)
192 if (getTAPVersion()!=
193 utils.getfirst(request.args, "version", getTAPVersion())):
194 return uwsactions.ErrorResource({
195 "msg": "Version mismatch; this service only supports"
196 " TAP version %s."%getTAPVersion(),
197 "type": "ValueError",
198 "hint": ""}), ()
199 if segments:
200 if segments[0]=='sync':
201 return getSyncResource(ctx, self.service, segments[1:]), ()
202 elif segments[0]=='async':
203 return asyncrender.getAsyncResource(
204 ctx, tap.WORKER_SYSTEM, "tap", self.service, segments[1:]), ()
205 elif segments[0]=='availability':
206 res = vosi.VOSIAvailabilityRenderer(ctx, self.service)
207 elif segments[0]=='capabilities':
208 res = vosi.VOSICapabilityRenderer(ctx, self.service)
209 elif segments[0]=='tables':
210 res = vosi.VOSITablesetRenderer(ctx, self.service)
211 elif segments[0]=='examples':
212 from gavo.web import examplesrender
213 res = examplesrender.Examples(ctx, self.service)
214 else:
215 raise svcs.UnknownURI("Bad TAP path %s"%"/".join(segments))
216 return res, segments[1:]
217 except svcs.UnknownURI:
218 raise
219 except base.Error as ex:
220
221 if not isinstance(ex, (base.ValidationError, uws.JobNotFound)):
222 base.ui.notifyError("TAP error")
223 return uwsactions.ErrorResource(ex), ()
224 raise common.UnknownURI("Bad TAP path %s"%"/".join(segments))
225