source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/LibraryServlet.java@ 36913

Last change on this file since 36913 was 36913, checked in by kjdon, 17 months ago

add servlet_context as a config param, so it can be used by xslt. needed for cookie consent path

  • Property svn:keywords set to Author Date Id Revision
File size: 49.0 KB
Line 
1/*
2 * LibraryServlet.java
3 * Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20package org.greenstone.gsdl3;
21
22import java.io.File;
23import java.io.IOException;
24import java.io.PrintWriter;
25import java.io.Serializable;
26import java.lang.reflect.Type;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Enumeration;
30import java.util.HashMap;
31import java.util.Hashtable;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35
36import javax.servlet.ServletConfig;
37import javax.servlet.ServletContext;
38import javax.servlet.ServletException;
39import javax.servlet.http.Cookie;
40import javax.servlet.http.HttpServletRequest;
41import javax.servlet.http.HttpServletResponse;
42import javax.servlet.http.HttpSession;
43import javax.servlet.http.HttpSessionBindingEvent;
44import javax.servlet.http.HttpSessionBindingListener;
45
46import org.apache.commons.fileupload.FileItem;
47import org.apache.commons.fileupload.disk.DiskFileItemFactory;
48import org.apache.commons.fileupload.servlet.ServletFileUpload;
49import org.apache.commons.lang3.StringUtils;
50import org.apache.log4j.Logger;
51import org.greenstone.gsdl3.action.PageAction;
52import org.greenstone.gsdl3.comms.Communicator;
53import org.greenstone.gsdl3.comms.SOAPCommunicator;
54import org.greenstone.gsdl3.core.DefaultReceptionist;
55import org.greenstone.gsdl3.core.MessageRouter;
56import org.greenstone.gsdl3.core.Receptionist;
57import org.greenstone.gsdl3.service.Authentication;
58import org.greenstone.gsdl3.util.Dictionary;
59import org.greenstone.gsdl3.util.GSConstants;
60import org.greenstone.gsdl3.util.GSParams;
61import org.greenstone.gsdl3.util.GSXML;
62import org.greenstone.gsdl3.util.UserContext;
63import org.greenstone.gsdl3.util.XMLConverter;
64import org.greenstone.util.GlobalProperties;
65import org.json.JSONObject;
66import org.w3c.dom.Document;
67import org.w3c.dom.Element;
68import org.w3c.dom.Node;
69import org.w3c.dom.NodeList;
70
71import com.google.gson.Gson;
72import com.google.gson.reflect.TypeToken;
73
74/**
75 * a servlet to serve the greenstone library - we are using servlets instead of
76 * cgi
77 * the init method is called only once - the first time the servlet classes
78 * are loaded. Each time a request comes in to the servlet, the session() method
79 * is called in a new thread (calls doGet/doPut etc) takes the a=p&p=home type
80 * args and builds a simple request to send to its receptionist, which returns a
81 * result in html, cos output=html is set in the request
82 *
83 * 18/Jul/07 xiao modify to make the cached parameters collection-specific. Most
84 * of the work is done in doGet(), except adding an inner class
85 * UserSessionCache.
86 *
87 * @see Receptionist
88 */
89public class LibraryServlet extends BaseGreenstoneServlet
90{
91 protected static final String LOGIN_MESSAGE_PARAM = "loginMessage";
92 protected static final String REDIRECT_URL_PARAM = "redirectURL";
93 /** the receptionist to send messages to */
94 protected Receptionist recept = null;
95
96 /** We record the library name for later */
97 protected String library_name = null;
98 /** Whether or not client-side XSLT support should be exposed */
99 protected boolean supports_client_xslt = false;
100
101 /**
102 * the default language - is specified by setting a servlet param, otherwise
103 * DEFAULT_LANG is used
104 */
105 protected String default_lang = null;
106 /**
107 * The default default - used if a default lang is not specified in the
108 * servlet params
109 */
110 protected final String DEFAULT_LANG = "en";
111
112 /**
113 * the cgi stuff - the Receptionist can add new args to this
114 *
115 * its used by the servlet to determine what args to save,
116 * and to set default values
117 */
118 protected GSParams gs_params = null;
119
120 /**
121 * a hash that contains all the active session IDs mapped to the cached
122 * items It is updated whenever the whole site or a particular collection is
123 * reconfigured using the command a=s&sa=c or a=s&sa=c&c=xxx It is in the
124 * form: sid -> (UserSessionCache object)
125 */
126 protected Hashtable<String, UserSessionCache> session_ids_table = new Hashtable<String, UserSessionCache>();
127
128 /**
129 * the maximum interval that the cached info remains in session_ids_table
130 * (in seconds) This is set in web.xml
131 */
132 protected int session_expiration = 1800;
133
134 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
135
136 /** initialise the servlet */
137 public void init(ServletConfig config) throws ServletException
138 {
139 // always call super.init;
140 super.init(config);
141 // disable preferences - does this work anyway??
142 //System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
143
144 // Look through all the init params
145 // these are the ones we are expecting
146 String interface_name = null;
147 String useXslt = null;
148 String sess_expire = null;
149 String site_name = null;
150 String recept_name = null;
151
152 // may have these instead of site_name
153 String remote_site_name = null;
154 String remote_site_type = null;
155 String remote_site_address = null;
156
157 // the stored config params
158 HashMap<String, Object> config_params = new HashMap<String, Object>();
159 Enumeration<String> params = config.getInitParameterNames();
160 while (params.hasMoreElements()) {
161 String name = params.nextElement();
162 String value = config.getInitParameter(name);
163 if (name.equals(GSConstants.LIBRARY_NAME)) {
164 library_name = value;
165 } else if (name.equals(GSConstants.INTERFACE_NAME)) {
166 interface_name = value;
167 } else if (name.equals(GSConstants.USE_CLIENT_SIDE_XSLT)) {
168 useXslt = value;
169 } else if (name.equals(GSConstants.DEFAULT_LANG)) {
170 this.default_lang = value;
171 } else if (name.equals(GSXML.SESSION_EXPIRATION)) {
172 sess_expire = value;
173 } else if (name.equals(GSConstants.SITE_NAME)) {
174 site_name = value;
175 } else if (name.equals(GSConstants.REMOTE_SITE_NAME)) {
176 remote_site_name = value;
177 } else if (name.equals(GSConstants.REMOTE_SITE_TYPE)) {
178 remote_site_type = value;
179 } else if (name.equals(GSConstants.REMOTE_SITE_ADDRESS)) {
180 remote_site_address = value;
181 } else if (name.equals(GSConstants.RECEPTIONIST_CLASS)) {
182 recept_name = value;
183 } else {
184 // If there is a param we are not expecting, just add to the list. That way users can add new servlet params which will go through to the XML source without modifying code.
185 config_params.put(name, value);
186 }
187 }
188 if (library_name == null || interface_name == null) {
189
190 // must have these
191 System.err.println("initialisation parameters not all set!");
192 System.err.println(" you must have libraryname and interfacename");
193 System.exit(1);
194 }
195
196 // If we don't have a site, then we must be using a Communicator, and all the remote params must be set
197 if (site_name == null && (remote_site_name == null || remote_site_type == null || remote_site_address == null)) {
198
199 System.err.println("initialisation paramters not all set!");
200 System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
201 System.exit(1);
202 }
203
204 supports_client_xslt = useXslt != null && useXslt.equals("true");
205 if (sess_expire != null && !sess_expire.equals(""))
206 {
207 this.session_expiration = Integer.parseInt(sess_expire);
208 }
209 if (this.default_lang == null)
210 {
211 // choose english
212 this.default_lang = DEFAULT_LANG;
213 }
214
215 config_params.put(GSConstants.LIBRARY_NAME, library_name);
216 config_params.put(GSConstants.INTERFACE_NAME, interface_name);
217 config_params.put(GSConstants.USE_CLIENT_SIDE_XSLT, supports_client_xslt);
218
219 if (site_name != null)
220 {
221 config_params.put(GSConstants.SITE_NAME, site_name);
222 }
223
224 String greenstone_context = GlobalProperties.getGSDL3WebAddress();
225 config_params.put(GSConstants.SERVLET_CONTEXT, greenstone_context);
226
227 // the receptionist -the servlet will talk to this
228 if (recept_name == null)
229 {
230 this.recept = new DefaultReceptionist();
231 }
232 else
233 {
234 try
235 {
236 this.recept = (Receptionist) Class.forName("org.greenstone.gsdl3.core." + recept_name).getDeclaredConstructor().newInstance();
237 }
238 catch (Exception e)
239 { // cant use this new one, so use normal one
240 System.err.println("LibraryServlet configure exception when trying to use a new Receptionist " + recept_name + ": " + e.getMessage());
241 e.printStackTrace();
242 this.recept = new DefaultReceptionist();
243 }
244 }
245 this.recept.setConfigParams(config_params);
246
247 // the params arg thingy
248
249 String params_name = (String) config.getInitParameter("params_class");
250 if (params_name == null)
251 {
252 this.gs_params = new GSParams();
253 }
254 else
255 {
256 try
257 {
258 this.gs_params = (GSParams) Class.forName("org.greenstone.gsdl3.util." + params_name).getDeclaredConstructor().newInstance();
259 }
260 catch (Exception e)
261 {
262 System.err.println("LibraryServlet configure exception when trying to use a new params thing " + params_name + ": " + e.getMessage());
263 e.printStackTrace();
264 this.gs_params = new GSParams();
265 }
266 }
267
268 // the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to the Receptionist, and the servlet never talks to it again directly.
269 if (site_name != null)
270 {
271 String mr_name = (String) config.getInitParameter("messagerouter_class");
272 MessageRouter message_router = null;
273 if (mr_name == null)
274 { // just use the normal MR
275 message_router = new MessageRouter();
276 }
277 else
278 { // try the specified one
279 try
280 {
281 message_router = (MessageRouter) Class.forName("org.greenstone.gsdl3.core." + mr_name).getDeclaredConstructor().newInstance();
282 }
283 catch (Exception e)
284 { // cant use this new one, so use normal one
285 System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter " + mr_name + ": " + e.getMessage());
286 e.printStackTrace();
287 message_router = new MessageRouter();
288 }
289 }
290
291 message_router.setSiteName(site_name);
292 message_router.setLibraryName(library_name);
293 message_router.setParams(this.gs_params);
294 message_router.configure();
295 this.recept.setMessageRouter(message_router);
296 }
297 else
298 {
299 // TODO: what do we do about params here?
300 // talking to a remote site, create a communicator
301 Communicator communicator = null;
302 // we need to create the XML to configure the communicator
303 Document doc = XMLConverter.newDOM();
304 Element site_elem = doc.createElement(GSXML.SITE_ELEM);
305 site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
306 site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
307 site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
308
309 if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA))
310 {
311 communicator = new SOAPCommunicator();
312 }
313 else
314 {
315 System.err.println("LibraryServlet.init Error: invalid Communicator type: " + remote_site_type);
316 System.exit(1);
317 }
318
319 if (!communicator.configure(site_elem))
320 {
321 System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
322 System.exit(1);
323 }
324 this.recept.setMessageRouter(communicator);
325 }
326
327 // pass params to the receptionist
328 this.recept.setParams(this.gs_params);
329 this.recept.configure();
330
331 //Allow the message router and the document to be accessed from anywhere in this servlet context
332 this.getServletContext().setAttribute(library_name+"Router", this.recept.getMessageRouter());
333 }
334
335 private void logUsageInfo(HttpServletRequest request, Map<String, String[]> queryMap)
336 {
337 String usageInfo = "";
338
339 //session-info: get params stored in the session
340 HttpSession session = request.getSession(true);
341 Enumeration attributeNames = session.getAttributeNames();
342 while (attributeNames.hasMoreElements())
343 {
344 String name = (String) attributeNames.nextElement();
345 usageInfo += name + "=" + session.getAttribute(name) + " ";
346 }
347
348 String queryParamStr = "";
349 if (queryMap != null)
350 {
351 Iterator<String> queryIter = queryMap.keySet().iterator();
352 while (queryIter.hasNext()) {
353 String q = queryIter.next();
354 String[] vals = queryMap.get(q);
355 queryParamStr += q +"="+StringUtils.join(vals, ",")+" ";
356 }
357 }
358 //logged info = general-info + session-info
359 usageInfo = request.getServletPath() + " " + //serlvet
360 "[" + queryParamStr.trim()+"]"+" " + // query map params
361 "session:[" + usageInfo.trim() + "]" + " " + // params stored in a session
362 request.getRemoteAddr() + " " + //remote address
363 request.getRequestedSessionId() + " " + //session id
364 request.getHeader("user-agent") + " "; //the remote brower info
365
366 logger.info(usageInfo);
367
368 }
369
370 public class UserSessionCache implements HttpSessionBindingListener
371 {
372 String session_id = "";
373
374 /**
375 * a hash that maps the session ID to a hashtable that maps the
376 * coll_name to its parameters coll_name -> Hashtable (param_name ->
377 * param_value)
378 */
379 protected Hashtable<String, Hashtable<String, String>> coll_name_params_table = null;
380
381 public UserSessionCache(String id, Hashtable<String, Hashtable<String, String>> table)
382 {
383 session_id = id;
384 coll_name_params_table = (table == null) ? new Hashtable() : table;
385 }
386
387 protected void cleanupCache(String coll_name)
388 {
389 if (coll_name_params_table.containsKey(coll_name))
390 {
391 coll_name_params_table.remove(coll_name);
392 }
393 }
394
395 protected Hashtable<String, Hashtable<String, String>> getParamsTable()
396 {
397 return coll_name_params_table;
398 }
399
400 public void valueBound(HttpSessionBindingEvent event)
401 {
402 // Do nothing
403 }
404
405 // if session cache id removed from session, this triggers this valueUnbound method on the value=this object
406 public void valueUnbound(HttpSessionBindingEvent event)
407 {
408 if (session_ids_table.containsKey(session_id))
409 {
410 session_ids_table.remove(session_id);
411 }
412 }
413
414 public int tableSize()
415 {
416 return (coll_name_params_table == null) ? 0 : coll_name_params_table.size();
417 }
418 }
419
420 public void destroy()
421 {
422 recept.cleanUp();
423 }
424
425 public void doGetOrPost(HttpServletRequest request, HttpServletResponse response, Map<String, String[]> queryMap) throws ServletException, IOException
426 {
427 logUsageInfo(request, queryMap);
428
429 if (processRedirectRequest(request, response, queryMap)) {
430 // this method will do the redirect if needed and return true if it has
431 // done so.
432 // e.g. el=direct/framed&rl=0&href=http://newurl.com
433 return;
434 }
435
436 // Nested Diagnostic Configurator to identify the client for
437 HttpSession session = request.getSession(true);
438 session.setMaxInactiveInterval(session_expiration);
439 String uid = session.getId();
440 request.setCharacterEncoding("UTF-8");
441 response.setContentType("text/html;charset=UTF-8");
442 PrintWriter out = response.getWriter();
443
444 String lang = getFirstParam(GSParams.LANGUAGE, queryMap);
445 if (lang == null || lang.equals(""))
446 {
447 // try the session cached lang
448 lang = (String) session.getAttribute(GSParams.LANGUAGE);
449 if (lang == null || lang.equals(""))
450 {
451 // still not set, use the default
452 lang = this.default_lang;
453 }
454 }
455
456 // set the lang in the session
457 session.setAttribute(GSParams.LANGUAGE, lang);
458
459 String output = getFirstParam(GSParams.OUTPUT, queryMap);
460 if (output == null || output.equals(""))
461 {
462 output = "html"; // uses html by default
463 }
464
465 String requestedURL = request.getRequestURL().toString();
466 String baseURL = "";
467 //logger.error("requested URL = "+requestedURL);
468 if (requestedURL.indexOf(library_name) != -1)
469 {
470 // we need to work out the baseURL and set it
471 baseURL = requestedURL;
472 int protocol_boundary_pos = baseURL.indexOf("://");
473 if (protocol_boundary_pos>=1) {
474 baseURL = baseURL.substring(protocol_boundary_pos+1); // change things like http:// or https:// to //
475 }
476 // The baseURL is everything up to the library_name.
477 // eg https://community.greenstone.org/greenstone3/library/collection/twso/page/about
478 // baseURL is //community.greenstone.org/greenstone3
479 // Issues: the library_name may occur in more than one place - eg if its part of the domain name mylibrary.heritage.nz/greenstone3/library
480 // or if a collection name is the same as the library name eg localhost:8585/greenstone3/twso/collection/twso/page/about.
481 // So can't just use teh first or last occurrence. Look for /library-name, and check its not the first position (eg //library.nzdl.org/greenstone3/library)
482 int library_name_index = baseURL.indexOf("/"+library_name);
483 if (library_name_index == 1) {
484 // we have library name at the start of the url - need to use the second one
485 library_name_index = baseURL.indexOf("/"+library_name, 2);
486 }
487 baseURL = baseURL.substring(0, library_name_index+1);
488 //logger.error("new base url = "+baseURL);
489
490 }
491
492 String fullURL;
493 if (request.getQueryString() != null)
494 {
495 fullURL = requestedURL + "?" + request.getQueryString();
496 }
497 else
498 {
499 fullURL = requestedURL;
500 }
501
502 UserContext userContext = new UserContext();
503 userContext.setLanguage(lang);
504 userContext.setUserID(uid);
505
506 if (!processLoginChanges(request, userContext, out, baseURL, queryMap, lang, output)) {
507 // any invalid login attempt will redirect to a new login page and return false
508 return;
509 }
510
511
512 if (request.getAuthType() != null)
513 {
514 // sets username, groups etc into usercontext
515 updateUserContextWithAuthenticatedInfo(request, userContext);
516 }
517
518 // If server output, force a switch to traditional interface
519 //output = (output.equals("server")) ? "html" : output;
520
521 // Force change the output mode if client-side XSLT is supported - server vs. client
522 // BUT only if the library allows client-side transforms
523 if (supports_client_xslt)
524 {
525 // MUST be done before the xml_message is built
526 Cookie[] cookies = request.getCookies();
527 Cookie xsltCookie = null;
528
529 // The client has cookies enabled and a value set - use it!
530 if (cookies != null)
531 {
532 for (Cookie c : cookies)
533 {
534 if (c.getName().equals("supportsXSLT"))
535 {
536 xsltCookie = c;
537 break;
538 }
539 }
540 output = (xsltCookie != null && xsltCookie.getValue().equals("true") && output.equals("html")) ? "xsltclient" : output;
541 }
542 }
543
544
545 String action = getFirstParam(GSParams.ACTION, queryMap);
546 String subaction = getFirstParam(GSParams.SUBACTION, queryMap);
547 String collection = getFirstParam(GSParams.COLLECTION, queryMap);
548 String document = getFirstParam(GSParams.DOCUMENT, queryMap);
549 String service = getFirstParam(GSParams.SERVICE, queryMap);
550 String specified_cache_key = getFirstParam(GSParams.CACHE_KEY, queryMap);
551
552 if (collection != null && !collection.equals("")) {
553 //is this user allowed to access this collection/document?
554 if (!runCollectionSecurityCheck(request, userContext, out, baseURL, collection, document, lang, output)) {
555 return;
556 }
557 }
558 // We clean up the cache session_ids_table if system
559 // commands are issued, and also don't need to do caching for these request requests
560 boolean should_cache = true;
561 if (action != null && action.equals(GSParams.SYSTEM_ACTION)
562 && !subaction.equals(GSXML.SYSTEM_TYPE_PING)
563 && !subaction.equals(GSXML.SYSTEM_TYPE_AUTHENTICATED_PING)) // don't 'clean' anything on a mere ping
564 {
565 should_cache = false;
566
567 // System commands now need to be logged in/have permissions
568 // like configuring, activation and deactivation
569 if(!configureSecurityCheck(request, userContext, out, baseURL, lang, output, queryMap)) {
570 return;
571 }
572
573 // we may want to remove all collection cache info, or just a specific collection
574 boolean clean_all = true;
575 String clean_collection = null;
576 // system commands are to activate/deactivate stuff
577 // collection param is in the sc parameter.
578 // don't like the fact that it is hard coded here
579 String coll = getFirstParam(GSParams.SYSTEM_CLUSTER, queryMap);
580 if (coll != null && !coll.equals(""))
581 {
582 clean_all = false;
583 clean_collection = coll;
584 }
585 else
586 {
587 // check other system types
588 if (subaction.equals("a") || subaction.equals("d"))
589 {
590 String module_name = getFirstParam("sn", queryMap);
591 if (module_name != null && !module_name.equals(""))
592 {
593 clean_all = false;
594 clean_collection = module_name;
595 }
596 }
597 }
598 if (clean_all)
599 {
600 // TODO
601 session_ids_table = new Hashtable<String, UserSessionCache>();
602 session.removeAttribute(GSParams.USER_SESSION_CACHE); // triggers valueUnbound(), which removes the session id from the session_ids_table
603 }
604 else
605 {
606 // just clean up info for clean_collection
607 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(session_ids_table.values());
608 for (int i = 0; i < cache_list.size(); i++)
609 {
610 UserSessionCache cache = cache_list.get(i);
611 cache.cleanupCache(clean_collection);
612 }
613
614 }
615 }
616
617 // cache_key is the collection name, or service name
618 String cache_key = specified_cache_key;
619 if (cache_key == null || cache_key.equals(""))
620 {
621 cache_key = collection;
622 }
623 if (cache_key == null || cache_key.equals(""))
624 {
625 cache_key = service;
626 }
627
628 //clear the collection-specific cache in the session, since we have no way to know whether this page is
629 //about the same collection as the last page or not.
630 Enumeration attributeNames = session.getAttributeNames();
631 while (attributeNames.hasMoreElements())
632 {
633 String name = (String) attributeNames.nextElement();
634 if (!name.equals(GSParams.USER_SESSION_CACHE) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT) && !this.gs_params.isGlobal(name))
635 {
636 session.removeAttribute(name);
637 }
638 }
639
640 UserSessionCache session_cache = null;
641 Hashtable<String, Hashtable<String, String>> param_table = null;
642 Hashtable<String, String> table = null;
643 boolean new_table = false;
644 String sid = session.getId();
645 boolean new_session = false;
646 if (!session_ids_table.containsKey(sid)) {
647 new_session = true;
648 }
649 if (should_cache == true && cache_key != null && !cache_key.equals(""))
650 {
651 if (!new_session)
652 {
653 session_cache = session_ids_table.get(sid);
654 param_table = session_cache.getParamsTable();
655 if (param_table.containsKey(cache_key))
656 {
657 table = param_table.get(cache_key);
658 }
659 else
660 {
661 table = new Hashtable<String, String>();
662 param_table.put(cache_key, table);
663 new_table = true;
664 }
665 }
666 else
667 {
668
669 param_table = new Hashtable<String, Hashtable<String, String>>();
670 table = new Hashtable<String, String>();
671 param_table.put(cache_key, table);
672 session_cache = new UserSessionCache(sid, param_table);
673 session_ids_table.put(sid, session_cache);
674 session.setAttribute(GSParams.USER_SESSION_CACHE, session_cache);
675 new_table = true;
676 }
677
678 }
679
680 // here we add in default params values if need be - if we have a new session, or if we have a new table
681 // in an existing session
682 // don't override any existing values
683 if (new_session || new_table) {
684
685 Iterator i = this.gs_params.getParamsWithDefaults().iterator();
686 while (i.hasNext()) {
687 String p = (String)i.next();
688 String v = this.gs_params.getParamDefault(p);
689 if (this.gs_params.isGlobal(p)) {
690 //need to add in to session unless its already there
691 if (session.getAttribute(p) == null) {
692 session.setAttribute(p, v);
693 }
694 } else {
695 // add to table unless its already there
696 if (new_table && !table.containsKey(p)) {
697 table.put(p,v);
698 }
699 }
700
701 }
702 }
703
704 // the request to the receptionist
705 Document msg_doc = XMLConverter.newDOM();
706 Element xml_message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
707 Element xml_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
708 xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
709
710 xml_message.appendChild(xml_request);
711
712 if (request.getAuthType() != null) {
713 // lots of classes are using the <userInformation> element. But all its info is now in userContext, so maybe we can get rid of this one day?
714 appendUserInformation(xml_request, userContext);
715 }
716
717 if (action == null || action.equals(""))
718 {
719 // display the home page - the default page
720 xml_request.setAttribute(GSXML.ACTION_ATT, "p");
721 xml_request.setAttribute(GSXML.SUBACTION_ATT, PageAction.HOME_PAGE);
722 }
723 else
724 {
725 xml_request.setAttribute(GSXML.ACTION_ATT, action);
726 if (subaction != null)
727 {
728 xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
729 }
730 }
731
732 // create the param list for the greenstone request - includes
733 // the params from the current request and any others from the saved session
734 Element xml_param_list = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
735 xml_request.appendChild(xml_param_list);
736
737 if (queryMap.containsKey("s1.collection") || queryMap.containsKey("s1.group")){
738 table.remove("s1.collection");
739 table.remove("s1.group");
740 }
741 for (String name : queryMap.keySet())
742 {
743 if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT))
744 {// we have already dealt with these
745
746 String value = "";
747 String[] values = queryMap.get(name);
748 value = values[0];
749 if (values.length > 1)
750 {
751 for (int i = 1; i < values.length; i++)
752 {
753 value += "," + values[i];
754 }
755 }
756 // if we need to save the value, then add it to the session/cache table.
757 // otherwise add directly to the paramList
758 if (this.gs_params.shouldSave(name)) {
759 if (this.gs_params.isGlobal(name) || table == null) {
760 session.setAttribute(name, value);
761 } else {
762 table.put(name, value);
763 }
764 }
765 else
766 {
767 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
768 param.setAttribute(GSXML.NAME_ATT, name);
769 param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
770 if (this.gs_params.isSensitive(name)) {
771 param.setAttribute(GSXML.SENSITIVE_ATT, "true");
772 }
773 xml_param_list.appendChild(param);
774
775 }
776 }
777 }
778 //put everything in the table into the session
779 if (table != null)
780 {
781 Enumeration<String> keys = table.keys();
782 while (keys.hasMoreElements())
783 {
784 String name = keys.nextElement();
785 session.setAttribute(name, table.get(name));
786 }
787 }
788
789 // put in all the params from the session cache
790 Enumeration params = session.getAttributeNames();
791 while (params.hasMoreElements())
792 {
793 String name = (String) params.nextElement();
794 if (!name.equals(GSParams.USER_SESSION_CACHE) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
795 {
796
797 // lang and uid are stored but we dont want it in the param list cos its already in the request
798 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
799 param.setAttribute(GSXML.NAME_ATT, name);
800 String value = GSXML.xmlSafe((String) session.getAttribute(name));
801
802 // ugly hack to undo : escaping
803 value = StringUtils.replace(value, "%3A", "\\:");
804 param.setAttribute(GSXML.VALUE_ATT, value);
805 xml_param_list.appendChild(param);
806 }
807 }
808
809
810 if (output.equals("json"))
811 {
812 response.setContentType("application/json");
813 }
814 else if (!output.equals("html") && !output.equals("server") && !output.equals("xsltclient"))
815 {
816 response.setContentType("text/xml"); // for now use text
817 }
818
819 //Add custom HTTP headers if requested
820 String httpHeadersParam = getFirstParam(GSParams.HTTP_HEADER_FIELDS, queryMap);
821 if (httpHeadersParam != null && httpHeadersParam.length() > 0)
822 {
823 Gson gson = new Gson();
824 Type type = new TypeToken<List<Map<String, String>>>()
825 {
826 }.getType();
827 List<Map<String, String>> httpHeaders = gson.fromJson(httpHeadersParam, type);
828 if (httpHeaders != null && httpHeaders.size() > 0)
829 {
830
831 for (int j = 0; j < httpHeaders.size(); j++)
832 {
833 Map nameValueMap = httpHeaders.get(j);
834 String name = (String) nameValueMap.get("name");
835 String value = (String) nameValueMap.get("value");
836
837 if (name != null && value != null)
838 {
839 response.setHeader(name, value);
840 }
841 }
842 }
843 }
844
845
846 xml_request.setAttribute("remoteAddress", request.getRemoteAddr());
847 xml_request.setAttribute("fullURL", fullURL.replace("&", "&amp;"));
848 xml_request.setAttribute("baseURL", baseURL);
849
850// logger.error("about to process this message");
851 // logger.error(XMLConverter.getPrettyString(xml_message));
852 Node xml_result = this.recept.process(xml_message);
853 encodeURLs(xml_result, response);
854
855 String xml_string = XMLConverter.getPrettyString(xml_result);
856
857 if (output.equals("json"))
858 {
859 try
860 {
861 JSONObject json_obj = org.json.XML.toJSONObject(xml_string);
862
863 out.println(json_obj.toString());
864 }
865 catch (Exception e)
866 {
867 e.printStackTrace();
868 out.println("Error: failed to convert output XML to JSON format");
869 }
870 }
871 else
872 {
873 out.println(xml_string);
874 }
875
876 displaySize(session_ids_table);
877 }
878
879 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
880 {
881 doGetOrPost(request, response, request.getParameterMap());
882 } //end of doGet(HttpServletRequest, HttpServletResponse)
883
884 private boolean processRedirectRequest(HttpServletRequest request, HttpServletResponse response, Map<String, String[]> queryMap) throws IOException
885 {
886 if (queryMap != null)
887 {
888 Iterator<String> queryIter = queryMap.keySet().iterator();
889 boolean redirect = false;
890 String href = null;
891 String rl = null;
892 String el = null;
893 String collection = null;
894
895 while (queryIter.hasNext())
896 {
897 String q = queryIter.next();
898 if (q.equals(GSParams.COLLECTION))
899 {
900 collection = queryMap.get(q)[0];
901 }
902 else if (q.equals(GSParams.EXTERNAL_LINK_TYPE))
903 {
904 el = queryMap.get(q)[0];
905 }
906 else if (q.equals(GSParams.HREF))
907 {
908 href = queryMap.get(q)[0];
909 href = StringUtils.replace(href, "%2f", "/");
910 href = StringUtils.replace(href, "%7e", "~");
911 href = StringUtils.replace(href, "%3f", "?");
912 href = StringUtils.replace(href, "%3A", "\\:");
913 }
914 else if (q.equals(GSParams.RELATIVE_LINK))
915 {
916 rl = queryMap.get(q)[0];
917 }
918 }
919
920 //if query_string contains "el=direct", an href is specified, and its not a relative link, then the web page will be redirected to the external URl, otherwise a greenstone page with an external URL will be displayed
921 //"rl=0" this is an external link
922 //"rl=1" this is an internal link
923 if ((href != null) && (rl.equals("0")))
924 {// This is an external link,
925
926 if (el.equals("framed"))
927 {
928 // framed means we are linking to an external page inside our greenstone page
929 HttpSession session = request.getSession();
930 ServletContext context = session.getServletContext();
931 String new_url = context.getContextPath()+"/"+ library_name+"?a=p&sa=html&url="+href;
932 if (collection != null && !collection.equals("")) {
933 new_url += "&c="+collection;
934 }
935 response.sendRedirect(new_url);
936 }
937 else
938 {
939 // el = '' or direct
940 //the web page is re-directed to the external URL (&el=&rl=0&href="http://...")
941 response.sendRedirect(href);
942 }
943 return true;
944 }
945 }
946 return false;
947 }
948
949 private void generateLoginPage(String redirect_url_string, String error_message, UserContext userContext, PrintWriter out, String baseURL, String output) {
950
951 Document loginPageDoc = XMLConverter.newDOM();
952 Element loginPageMessage = loginPageDoc.createElement(GSXML.MESSAGE_ELEM);
953 Element loginPageRequest = GSXML.createBasicRequest(loginPageDoc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
954 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
955 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
956 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, output);
957 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
958
959 loginPageMessage.appendChild(loginPageRequest);
960
961 Element paramList = loginPageDoc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
962 loginPageRequest.appendChild(paramList);
963
964 Element messageParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
965 messageParam.setAttribute(GSXML.NAME_ATT, LOGIN_MESSAGE_PARAM);
966 messageParam.setAttribute(GSXML.VALUE_ATT, error_message);
967 paramList.appendChild(messageParam);
968
969 Element urlParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
970 urlParam.setAttribute(GSXML.NAME_ATT, REDIRECT_URL_PARAM);
971
972 if (redirect_url_string.matches("^[a-z]+://.*$")) {
973 int protocol_boundary_pos = redirect_url_string.indexOf("://");
974 redirect_url_string = redirect_url_string.substring(protocol_boundary_pos+1); // change things like http:// or https:// to //
975 }
976
977 urlParam.setAttribute(GSXML.VALUE_ATT, redirect_url_string);
978 paramList.appendChild(urlParam);
979
980 Node loginPageResponse = this.recept.process(loginPageMessage);
981 out.println(XMLConverter.getPrettyString(loginPageResponse));
982 }
983
984 private boolean processLoginChanges(HttpServletRequest request, UserContext userContext, PrintWriter out, String baseURL, Map<String, String[]> queryMap, String lang, String output) throws ServletException {
985
986 //Check if we need to login or logout
987 String username = getFirstParam(GSParams.USERNAME, queryMap);
988 String password = getFirstParam(GSParams.PASSWORD, queryMap);
989 String logout = getFirstParam(GSParams.LOGOUT, queryMap);
990
991 if (logout != null)
992 {
993 request.logout();
994 }
995
996 if (username != null && password != null)
997 {
998 //We are changing to another user, so log out first
999 if (request.getAuthType() != null)
1000 {
1001 request.logout();
1002 }
1003
1004 //This try/catch block catches when the login request fails (e.g. The user enters an incorrect password).
1005 try
1006 {
1007 //Try a global login first
1008 password = Authentication.hashPassword(password);
1009 request.login(username, password);
1010 }
1011 catch (Exception ex)
1012 {
1013 try
1014 {
1015 //If the global login fails then try a site-level login
1016 String siteName = (String) this.recept.getConfigParams().get(GSConstants.SITE_NAME);
1017 request.login(siteName + "-" + username, password);
1018
1019 }
1020 catch (Exception exc)
1021 {
1022 //The user entered in either the wrong username or the wrong password
1023
1024 HttpSession session = request.getSession();
1025 ServletContext context = session.getServletContext();
1026 String redirect_url_string = request.getRequestURI().replaceFirst(context.getContextPath() + "/", "");
1027
1028 if ((request.getQueryString() != null) && (request.getQueryString().length() > 0))
1029 {
1030 redirect_url_string += "?" + request.getQueryString().replace("&", "&amp;");
1031 }
1032
1033 generateLoginPage(redirect_url_string, getTextString("auth.error.un_or_pw_err", lang), userContext, out, baseURL, output);
1034 return false;
1035 }
1036 }
1037 }
1038 return true;
1039
1040
1041 }
1042
1043 private void updateUserContextWithAuthenticatedInfo(HttpServletRequest request, UserContext userContext)
1044 {
1045
1046 //Get the username
1047 String user_name = request.getUserPrincipal().getName();
1048 userContext.setUsername(user_name);
1049
1050 //Get the groups for the user
1051 Document msg_doc = XMLConverter.newDOM();
1052 Element userInfoMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1053 Element userInfoRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_PROCESS, "GetUserInformation", userContext);
1054 userInfoMessage.appendChild(userInfoRequest);
1055
1056 Element paramList = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1057 userInfoRequest.appendChild(paramList);
1058 paramList.appendChild(GSXML.createParameter(msg_doc, GSXML.USERNAME_ATT, user_name));
1059
1060 Element userInfoResponseMessage = (Element) this.recept.process(userInfoMessage);
1061 Element userInfoResponse = (Element) GSXML.getChildByTagName(userInfoResponseMessage, GSXML.RESPONSE_ELEM);
1062 Element respParamList = (Element) GSXML.getChildByTagName(userInfoResponse, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1063
1064 if (respParamList != null)
1065 {
1066 HashMap<String, Serializable> params = GSXML.extractParams(respParamList, false);
1067 String groups = (String) params.get("groups");
1068 String editEnabled = (String) params.get("editEnabled");
1069 userContext.setGroups(groups.split(","));
1070 userContext.setEditEnabled((editEnabled != null) ? editEnabled : "false");
1071 }
1072 }
1073
1074 private void appendUserInformation(Element xml_request, UserContext userContext)
1075 {
1076 Element userInformation = xml_request.getOwnerDocument().createElement(GSXML.USER_INFORMATION_ELEM);
1077 userInformation.setAttribute(GSXML.USERNAME_ATT, userContext.getUsername());
1078
1079
1080 userInformation.setAttribute(GSXML.GROUPS_ATT, userContext.getGroupsString());
1081 userInformation.setAttribute(GSXML.EDIT_ENABLED_ATT, userContext.getEditEnabled());
1082 xml_request.appendChild(userInformation);
1083 }
1084
1085 /**
1086 * request.getRemoteAddr() returns the IP of the client *or* of a proxy.
1087 * We want the client IP, so we can check if it's truly local or not, since proxies can be
1088 * local, thus masking a client connecting from an external IP.
1089 * The following code is from
1090 * https://www.javaprogramto.com/2020/11/how-to-get-client-ip-address-in-java.html
1091 */
1092 public String getClientIpAddress(HttpServletRequest request)
1093 {
1094 final String[] VALID_IP_HEADER_CANDIDATES = {
1095 "X-Forwarded-For",
1096 "Proxy-Client-IP",
1097 "WL-Proxy-Client-IP",
1098 "HTTP_X_FORWARDED_FOR",
1099 "HTTP_X_FORWARDED",
1100 "HTTP_X_CLUSTER_CLIENT_IP",
1101 "HTTP_CLIENT_IP",
1102 "HTTP_FORWARDED_FOR",
1103 "HTTP_FORWARDED",
1104 "HTTP_VIA",
1105 "REMOTE_ADDR"
1106 };
1107
1108
1109 for (String header : VALID_IP_HEADER_CANDIDATES) {
1110 String ipAddress = request.getHeader(header);
1111 if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
1112 return ipAddress;
1113 }
1114 }
1115 return request.getRemoteAddr(); // fallback to whatever is the incoming IP (could be proxy)
1116 }
1117
1118
1119 /**
1120 * Clients on the same machine as the GS3 server can reconfigure and activate/deactivate,
1121 * Users in the administrator group also have the right to do such system commands.
1122 * For collection-level system commands, users with permissions to edit all collections or
1123 * the specific collection have a right to activate/deactivate a collection.
1124 * Useful links:
1125 * https://stackoverflow.com/questions/13563351/how-to-restrict-acces-to-specific-servlet-by-ip-via-container-configuration
1126 * https://stackoverflow.com/questions/35015514/restricting-access-to-localhost-for-java-servlet-endpoint
1127 * Reverse of: https://stackoverflow.com/questions/2539461/how-to-access-java-servlet-running-on-my-pc-from-outside
1128 */
1129 private boolean configureSecurityCheck(HttpServletRequest request, UserContext userContext,
1130 PrintWriter out, String baseURL, String lang,
1131 String output, Map<String, String[]> queryMap)
1132 {
1133 // if request emanates on same machine as GS server/from local machine, let it go through
1134 String ipOfClient = getClientIpAddress(request); //request.getRemoteAddr();
1135
1136 // Load the global.properties file, get the tomcat.server.IPregex and check for any of it
1137 // matching against the local IP
1138 String tomcatServerIPregex = GlobalProperties.getProperty("tomcat.server.IPregex", "");
1139 if(ipOfClient.equals(request.getLocalAddr()) || ipOfClient.matches(tomcatServerIPregex)) {
1140 return true;
1141 }
1142
1143 // TODO: Want regex for localhost situations and then make it a property in build.props
1144 // In build.props: comment, you might like to leave the IP of your server machine
1145 // at the end of the line
1146 // Check with another machine: browser, retest cmdline and activate.pl
1147 // Final phase is testing with apache set up
1148
1149 // if we have sc=colname, user needs to be colname-|all-collection-editor
1150 // if we have st=collection&sn=colname, same as above
1151 // otherwise user needs to be administrator
1152
1153 // We can have MODULE_TYPE=collection And MODULE_NAME=collname,
1154 // OR SYSTEM_CLUSTER=collname
1155 // If none of these specified, then assume the user should be administrator
1156 // If not a collection level operation, the user should be administrator
1157
1158 String coll = null;
1159 String module_type = getFirstParam(GSParams.SYSTEM_MODULE_TYPE, queryMap);
1160 if(module_type != null && module_type.equals("collection")) {
1161 // To deactivate demo:library?excerptid=gs_content&a=s&sa=d&sc=lucene-jdbm-demo
1162 coll = getFirstParam(GSParams.SYSTEM_MODULE_NAME, queryMap);
1163 } else {
1164 // To reconfigure demo: library?excerptid=gs_content&a=s&sa=c&sc=lucene-jdbm-demo
1165 coll = getFirstParam(GSParams.SYSTEM_CLUSTER, queryMap);
1166 if (coll != null && coll.equals("")) {
1167 coll = null;
1168 }
1169 }
1170 String collname_editor = (coll == null) ? null : (coll+"-collections-editor");
1171
1172 for (String group : userContext.getGroups()) {
1173
1174 // if user is admin, all is good: they can do reconfigure (on service, collection or
1175 // any module) or activate/deactivate a collection or any module
1176 if (group.equals("administrator")) {
1177 return true;
1178 }
1179
1180 // if collection level operation, user must have permissions for the collection
1181 // so the user must be in at least one of all-|personal-|collname-collections-editor
1182 if (coll != null) { // collname_editor won't be null
1183 if(group.equals("all-collections-editor") || group.equals(collname_editor)) {
1184 return true; // do we add || group.equals("personal-collections-editor")?
1185 }
1186 }
1187
1188 }
1189
1190 errorAndLoginPage(request, userContext, out, baseURL, lang, output);
1191 return false;
1192 }
1193
1194 private boolean runCollectionSecurityCheck(HttpServletRequest request, UserContext userContext, PrintWriter out, String baseURL, String collection, String document, String lang, String output) {
1195
1196 //Get the security info for this collection
1197 Document msg_doc = XMLConverter.newDOM();
1198 Element securityMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1199 Element securityRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_SECURITY, collection, userContext);
1200 securityMessage.appendChild(securityRequest);
1201 if (document != null && !document.equals(""))
1202 {
1203 securityRequest.setAttribute(GSXML.NODE_OID, document);
1204 }
1205
1206 Element securityResponse = (Element) GSXML.getChildByTagName(this.recept.process(securityMessage), GSXML.RESPONSE_ELEM);
1207 if (securityResponse == null)
1208 {
1209 return false;
1210 }
1211
1212 // Groups mentioned in collectionConfig.xml's Security element, se_groups
1213 ArrayList<String> se_groups = GSXML.getGroupsFromSecurityResponse(securityResponse);
1214
1215 //If guests are not allowed to access this page then check to see if the user is in a group that is allowed to access the page
1216 if (!se_groups.contains(""))
1217 {
1218 boolean found = false;
1219 for (String se_group : se_groups)
1220 {
1221 if (request.isUserInRole(se_group))
1222 {
1223 found = true;
1224 break;
1225 }
1226 }
1227
1228 //The current user is not allowed to access the page so produce a login page
1229 if (!found)
1230 {
1231 errorAndLoginPage(request, userContext, out, baseURL, lang, output);
1232 return false;
1233 }
1234 }
1235 return true;
1236 }
1237
1238
1239 private void errorAndLoginPage(HttpServletRequest request, UserContext userContext,
1240 PrintWriter out, String baseURL, String lang, String output)
1241 {
1242 String error_message = "";
1243 if (request.getAuthType() == null)
1244 {
1245 error_message = getTextString("auth.error.login", lang);
1246 }
1247 else
1248 {
1249 error_message = getTextString("auth.error.incorrect_login", lang);
1250 }
1251
1252 HttpSession session = request.getSession();
1253 ServletContext context = session.getServletContext();
1254 String redirect_url_string = request.getRequestURI().replaceFirst(context.getContextPath() + "/", "");
1255
1256 if (request.getQueryString() != null && request.getQueryString().length() > 0)
1257 {
1258 redirect_url_string += "?" + request.getQueryString().replace("&", "&amp;");
1259 }
1260
1261 generateLoginPage(redirect_url_string, error_message, userContext, out, baseURL, output);
1262 }
1263
1264
1265 private String getTextString(String key, String lang) {
1266 return Dictionary.getTextString(key, lang, null, null, null, null, null);
1267
1268 }
1269 //a debugging method
1270 private void displaySize(Hashtable<String, UserSessionCache> table)
1271 {
1272 if (table == null)
1273 {
1274 //logger.info("cached table is null");
1275 return;
1276 }
1277 if (table.size() == 0)
1278 {
1279 //logger.info("cached table size is zero");
1280 return;
1281 }
1282 int num_cached_coll = 0;
1283 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(table.values());
1284 for (int i = 0; i < cache_list.size(); i++)
1285 {
1286 num_cached_coll += cache_list.get(i).tableSize();
1287 }
1288 //logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
1289 }
1290
1291 /** merely a debugging method! */
1292 private String tableToString(Hashtable<String, Hashtable<String, String>> table)
1293 {
1294 String str = "";
1295 Enumeration<String> keys = table.keys();
1296 while (keys.hasMoreElements())
1297 {
1298 String name = keys.nextElement();
1299 str += name + ", ";
1300 }
1301 return str;
1302 }
1303
1304 /**
1305 * this goes through each URL and adds in a session id if needed-- its
1306 * needed if the browser doesn't accept cookies also escapes things if
1307 * needed
1308 */
1309 protected void encodeURLs(Node dataNode, HttpServletResponse response)
1310 {
1311 if (dataNode == null)
1312 {
1313 return;
1314 }
1315
1316 Element data = null;
1317
1318 short nodeType = dataNode.getNodeType();
1319 if (nodeType == Node.DOCUMENT_NODE)
1320 {
1321 Document docNode = (Document) dataNode;
1322 data = docNode.getDocumentElement();
1323 }
1324 else
1325 {
1326 data = (Element) dataNode;
1327 }
1328
1329 if (data != null)
1330 {
1331
1332 // get all the <a> elements
1333 NodeList hrefs = data.getElementsByTagName("a");
1334 // Instead of calculating each iteration...
1335 int hrefscount = hrefs.getLength();
1336
1337 for (int i = 0; hrefs != null && i < hrefscount; i++)
1338 {
1339 Element a = (Element) hrefs.item(i);
1340 // ugly hack to get rid of : in the args - interferes with session handling
1341 String href = a.getAttribute("href");
1342 if (!href.equals(""))
1343 {
1344 if (href.indexOf("?") != -1)
1345 {
1346 String[] parts = StringUtils.split(href, "\\?", -1);
1347 if (parts.length == 1)
1348 {
1349 parts[0] = StringUtils.replace(parts[0], ":", "%3A");
1350 href = "?" + parts[0];
1351 }
1352 else
1353 {
1354 parts[1] = StringUtils.replace(parts[1], ":", "%3A");
1355 href = parts[0] + "?" + parts[1];
1356 }
1357
1358 }
1359 a.setAttribute("href", response.encodeURL(href));
1360 }
1361 }
1362
1363 // now find any submit bits - get all the <form> elements
1364 NodeList forms = data.getElementsByTagName("form");
1365 int formscount = forms.getLength();
1366 for (int i = 0; forms != null && i < formscount; i++)
1367 {
1368 Element form = (Element) forms.item(i);
1369 form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
1370 }
1371 // are these the only cases where URLs occur??
1372 // we should only do this for greenstone urls?
1373 }
1374
1375 }
1376
1377 protected String getFirstParam(String name, Map<String, String[]> map)
1378 {
1379 String[] val = map.get(name);
1380 if (val == null || val.length == 0)
1381 {
1382 return null;
1383 }
1384
1385 return val[0];
1386 }
1387
1388 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
1389 {
1390 //Check if we need to process a file upload
1391 if (ServletFileUpload.isMultipartContent(request))
1392 {
1393 DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
1394
1395 int sizeLimit = System.getProperties().containsKey("servlet.upload.filesize.limit") ? Integer.parseInt(System.getProperty("servlet.upload.filesize.limit")) : 100 * 1024 * 1024;
1396
1397 File tempDir = new File(GlobalProperties.getGSDL3Home() + File.separator + "tmp");
1398 if (!tempDir.exists())
1399 {
1400 tempDir.mkdirs();
1401 }
1402
1403 //We want all files to be stored on disk (hence the 0)
1404 fileItemFactory.setSizeThreshold(0);
1405 fileItemFactory.setRepository(tempDir);
1406
1407 ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
1408 uploadHandler.setFileSizeMax(sizeLimit);
1409
1410 HashMap<String, String[]> queryMap = new HashMap<String, String[]>();
1411 try
1412 {
1413 List items = uploadHandler.parseRequest(request);
1414 Iterator iter = items.iterator();
1415 while (iter.hasNext())
1416 {
1417 FileItem current = (FileItem) iter.next();
1418 if (current.isFormField())
1419 {
1420 queryMap.put(current.getFieldName(), new String[] { current.getString() });
1421 }
1422 else if (current.getName() != null && !current.getName().equals(""))
1423 {
1424 File file = new File(tempDir, current.getName());
1425 current.write(file);
1426
1427 queryMap.put("md___ex.Filesize", new String[] { "" + file.length() });
1428 queryMap.put("md___ex.Filename", new String[] { "" + current.getName() });
1429 }
1430 }
1431 }
1432 catch (Exception e)
1433 {
1434 e.printStackTrace();
1435 }
1436
1437 doGetOrPost(request, response, queryMap);
1438 }
1439 else
1440 {
1441 doGetOrPost(request, response, request.getParameterMap());
1442 }
1443 }
1444}
Note: See TracBrowser for help on using the repository browser.