1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts.util;
22
23 import java.lang.reflect.InvocationTargetException;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.regex.Pattern;
34
35 import org.apache.commons.beanutils.BeanUtils;
36 import org.apache.commons.beanutils.PropertyUtils;
37 import org.apache.struts.Globals;
38 import org.apache.struts.action.ActionForm;
39 import org.apache.struts.action.ActionMapping;
40 import org.apache.struts.action.ActionRedirect;
41 import org.apache.struts.action.ActionServlet;
42 import org.apache.struts.action.ActionServletWrapper;
43 import org.apache.struts.config.ActionConfig;
44 import org.apache.struts.config.FormBeanConfig;
45 import org.apache.struts.config.ForwardConfig;
46 import org.apache.struts.config.ModuleConfig;
47 import org.apache.struts.upload.FormFile;
48 import org.apache.struts.upload.MultipartRequestHandler;
49 import org.apache.struts.upload.MultipartRequestWrapper;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import jakarta.servlet.ServletContext;
54 import jakarta.servlet.ServletException;
55 import jakarta.servlet.http.HttpServletRequest;
56 import jakarta.servlet.http.HttpSession;
57
58
59
60
61
62
63
64 public class RequestUtils {
65
66
67
68
69
70 private final static Logger LOG =
71 LoggerFactory.getLogger(RequestUtils.class);
72
73
74
75
76 protected static final Pattern CLASS_ACCESS_PATTERN = Pattern
77 .compile("(.*\\.|^|.*|\\[('|\"))class(\\.|('|\")]|\\[).*",
78 Pattern.CASE_INSENSITIVE);
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public static URL absoluteURL(HttpServletRequest request, String path)
93 throws MalformedURLException {
94 return (new URL(serverURL(request), request.getContextPath() + path));
95 }
96
97
98
99
100
101
102
103
104
105 public static Class<?> applicationClass(String className)
106 throws ClassNotFoundException {
107 return applicationClass(className, null);
108 }
109
110
111
112
113
114
115
116
117
118
119 public static Class<?> applicationClass(String className,
120 ClassLoader classLoader)
121 throws ClassNotFoundException {
122 if (classLoader == null) {
123
124 classLoader = Thread.currentThread().getContextClassLoader();
125
126 if (classLoader == null) {
127 classLoader = RequestUtils.class.getClassLoader();
128 }
129 }
130
131
132 return (classLoader.loadClass(className));
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 public static Object applicationInstance(String className)
153 throws ClassNotFoundException, IllegalAccessException,
154 InstantiationException {
155 return applicationInstance(className, null);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public static Object applicationInstance(String className,
177 ClassLoader classLoader)
178 throws ClassNotFoundException, IllegalAccessException,
179 InstantiationException {
180
181 try {
182 return applicationClass(className, classLoader)
183 .getDeclaredConstructor()
184 .newInstance();
185 } catch (IllegalArgumentException | InvocationTargetException
186 | NoSuchMethodException | SecurityException
187 | ClassNotFoundException e) {
188 InstantiationException e2 =
189 new InstantiationException("Error creating " + className + " instance");
190 e2.initCause(e);
191 throw e2;
192 }
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206 public static ActionForm createActionForm(HttpServletRequest request,
207 ActionMapping mapping, ModuleConfig moduleConfig, ActionServlet servlet) {
208
209 String attribute = mapping.getAttribute();
210
211 if (attribute == null) {
212 return (null);
213 }
214
215
216 String name = mapping.getName();
217 FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
218
219 if (config == null) {
220 LOG.warn("No FormBeanConfig found under '{}'", name);
221
222 return (null);
223 }
224
225 ActionForm instance =
226 lookupActionForm(request, attribute, mapping.getScope());
227
228
229 if ((instance != null) && config.canReuse(instance)) {
230 return (instance);
231 }
232
233 return createActionForm(config, servlet);
234 }
235
236 private static ActionForm lookupActionForm(HttpServletRequest request,
237 String attribute, String scope) {
238
239 LOG.debug(" Looking for ActionForm bean instance in scope '{}' "
240 + "under attribute key '{}'", scope, attribute);
241
242 ActionForm instance = null;
243 HttpSession session = null;
244
245 if ("request".equals(scope)) {
246 instance = (ActionForm) request.getAttribute(attribute);
247 } else {
248 session = request.getSession();
249 instance = (ActionForm) session.getAttribute(attribute);
250 }
251
252 return (instance);
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266
267 public static ActionForm createActionForm(FormBeanConfig config,
268 ActionServlet servlet) {
269 if (config == null) {
270 return (null);
271 }
272
273 ActionForm instance = null;
274
275
276 try {
277 instance = config.createActionForm(servlet);
278
279 LOG.atDebug()
280 .setMessage(" Creating new {} instance of type '{}'")
281 .addArgument(() -> config.getDynamic() ? "DynaActionForm" : "ActionForm")
282 .addArgument(config.getType())
283 .log();
284 LOG.trace(" --> {}", instance);
285 } catch (Throwable t) {
286 LOG.atError()
287 .setMessage(() -> servlet.getInternal().getMessage("formBean",
288 config.getType()))
289 .setCause(t)
290 .log();
291 }
292
293 return (instance);
294 }
295
296
297
298
299
300
301
302
303 public static String getServletMapping(ActionServlet servlet) {
304 ServletContext servletContext = servlet.getServletConfig().getServletContext();
305 return (String)servletContext.getAttribute(Globals.SERVLET_KEY);
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319 public static Locale getUserLocale(HttpServletRequest request, String locale) {
320 Locale userLocale = null;
321 HttpSession session = request.getSession(false);
322
323 if (locale == null) {
324 locale = Globals.LOCALE_KEY;
325 }
326
327
328 if (session != null) {
329 userLocale = (Locale) session.getAttribute(locale);
330 }
331
332 if (userLocale == null) {
333
334 userLocale = request.getLocale();
335 }
336
337 return userLocale;
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353 public static void populate(Object bean, HttpServletRequest request)
354 throws ServletException {
355 populate(bean, null, null, request);
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 public static void populate(Object bean, String prefix, String suffix,
384 HttpServletRequest request)
385 throws ServletException {
386
387 HashMap<String, Object> properties = new HashMap<>();
388
389
390 Enumeration<String> names = null;
391
392
393 Map<String, Object> multipartParameters = null;
394
395 String contentType = request.getContentType();
396 String method = request.getMethod();
397 boolean isMultipart = false;
398
399 if (bean instanceof ActionForm) {
400 ((ActionForm) bean).setMultipartRequestHandler(null);
401 }
402
403 MultipartRequestHandler multipartHandler = null;
404 if ((contentType != null)
405 && (contentType.startsWith("multipart/form-data"))
406 && (method.equalsIgnoreCase("POST"))) {
407
408 ActionServletWrapper servlet;
409
410 if (bean instanceof ActionForm) {
411 servlet = ((ActionForm) bean).getServletWrapper();
412 } else {
413 throw new ServletException("bean that's supposed to be "
414 + "populated from a multipart request is not of type "
415 + "\"org.apache.struts.action.ActionForm\", but type "
416 + "\"" + bean.getClass().getName() + "\"");
417 }
418
419
420 multipartHandler = getMultipartHandler(request);
421
422 if (multipartHandler != null) {
423 isMultipart = true;
424
425
426 servlet.setServletFor(multipartHandler);
427 multipartHandler.setMapping((ActionMapping) request
428 .getAttribute(Globals.MAPPING_KEY));
429
430
431 multipartHandler.handleRequest(request);
432
433
434 Boolean maxLengthExceeded =
435 (Boolean) request.getAttribute(MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED);
436
437 if ((maxLengthExceeded != null)
438 && (maxLengthExceeded.booleanValue())) {
439 ((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
440 return;
441 }
442
443
444 multipartParameters =
445 getAllParametersForMultipartRequest(request,
446 multipartHandler);
447 names = Collections.enumeration(multipartParameters.keySet());
448 }
449 }
450
451 if (!isMultipart) {
452 names = request.getParameterNames();
453 }
454
455 while (names.hasMoreElements()) {
456 String name = names.nextElement();
457 String stripped = name;
458
459 if (prefix != null) {
460 if (!stripped.startsWith(prefix)) {
461 continue;
462 }
463
464 stripped = stripped.substring(prefix.length());
465 }
466
467 if (suffix != null) {
468 if (!stripped.endsWith(suffix)) {
469 continue;
470 }
471
472 stripped =
473 stripped.substring(0, stripped.length() - suffix.length());
474 }
475
476 Object parameterValue = null;
477
478 if (isMultipart) {
479 parameterValue = multipartParameters.get(name);
480 parameterValue = rationalizeMultipleFileProperty(bean, name, parameterValue);
481 } else {
482 parameterValue = request.getParameterValues(name);
483 }
484
485
486
487 if (CLASS_ACCESS_PATTERN.matcher(stripped).matches()) {
488
489 LOG.trace("ignore parameter: paramName={}", stripped);
490 continue;
491 }
492
493
494
495 if (!(stripped.startsWith("org.apache.struts."))) {
496 properties.put(stripped, parameterValue);
497 }
498 }
499
500
501 try {
502 BeanUtils.populate(bean, properties);
503 } catch (Exception e) {
504 throw new ServletException("BeanUtils.populate", e);
505 } finally {
506 if (multipartHandler != null) {
507
508
509
510
511 ((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
512 }
513 }
514 }
515
516
517
518
519
520
521
522
523
524 public static void populate(ActionRedirect redirect, HttpServletRequest request) {
525 assert (redirect != null) : "redirect is required";
526 assert (request != null) : "request is required";
527
528 Enumeration<String> e = request.getParameterNames();
529 while (e.hasMoreElements()) {
530 String name = e.nextElement();
531 String[] values = request.getParameterValues(name);
532 redirect.addParameter(name, values);
533 }
534 }
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549 private static Object rationalizeMultipleFileProperty(Object bean,
550 String name, Object parameterValue) throws ServletException {
551
552 if (!(parameterValue instanceof FormFile[])) {
553 return parameterValue;
554 }
555
556 final FormFile[] formFileValue = (FormFile[]) parameterValue;
557 try {
558 final Class<?> propertyType =
559 PropertyUtils.getPropertyType(bean, name);
560
561 if (propertyType == null) {
562 return parameterValue;
563 }
564
565 if (List.class.isAssignableFrom(propertyType)) {
566 return Arrays.asList(formFileValue);
567 }
568
569 if (FormFile.class.isAssignableFrom(propertyType)) {
570 switch (formFileValue.length) {
571 case 0:
572 LOG.error("FormFile-parameter \"{}\" for FormBean "
573 + "\"{}\" has unexpected length of null!",
574 name, bean.getClass().getName());
575 return null;
576
577 case 1:
578 return formFileValue[0];
579
580 default:
581 LOG.error("FormFile-parameter \"{}\" for FormBean "
582 + "\"{}\" should have an Array or a List as "
583 + "method parameter!", name,
584 bean.getClass().getName());
585 return formFileValue[0];
586 }
587 }
588 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
589 throw new ServletException(e);
590 }
591
592
593 return parameterValue;
594 }
595
596
597
598
599
600
601
602
603
604
605
606
607
608 private static MultipartRequestHandler getMultipartHandler(
609 HttpServletRequest request)
610 throws ServletException {
611 MultipartRequestHandler multipartHandler = null;
612 String multipartClass =
613 (String) request.getAttribute(Globals.MULTIPART_KEY);
614
615 request.removeAttribute(Globals.MULTIPART_KEY);
616
617
618 if (multipartClass != null) {
619 try {
620 multipartHandler =
621 (MultipartRequestHandler) applicationInstance(multipartClass);
622 } catch (ClassNotFoundException cnfe) {
623 LOG.error("MultipartRequestHandler class \"{}\" "
624 + "in mapping class not found, "
625 + "defaulting to global multipart class", multipartClass);
626 } catch (InstantiationException ie) {
627 LOG.error("InstantiationException when instantiating "
628 + "MultipartRequestHandler \"{}\", "
629 + "defaulting to global multipart class, exception: {}",
630 multipartClass, ie.getMessage());
631 } catch (IllegalAccessException iae) {
632 LOG.error("IllegalAccessException when instantiating "
633 + "MultipartRequestHandler \"{}\", "
634 + "defaulting to global multipart class, exception: {}",
635 multipartClass, iae.getMessage());
636 }
637
638 if (multipartHandler != null) {
639 return multipartHandler;
640 }
641 }
642
643 ModuleConfig moduleConfig =
644 ModuleUtils.getInstance().getModuleConfig(request);
645
646 multipartClass = moduleConfig.getControllerConfig().getMultipartClass();
647
648
649 if (multipartClass != null) {
650 try {
651 multipartHandler =
652 (MultipartRequestHandler) applicationInstance(multipartClass);
653 } catch (ClassNotFoundException cnfe) {
654 throw new ServletException("Cannot find multipart class \""
655 + multipartClass + "\"", cnfe);
656 } catch (InstantiationException ie) {
657 throw new ServletException(
658 "InstantiationException when instantiating "
659 + "multipart class \"" + multipartClass + "\"", ie);
660 } catch (IllegalAccessException iae) {
661 throw new ServletException(
662 "IllegalAccessException when instantiating "
663 + "multipart class \"" + multipartClass + "\"", iae);
664 }
665
666 if (multipartHandler != null) {
667 return multipartHandler;
668 }
669 }
670
671 return multipartHandler;
672 }
673
674
675
676
677
678
679
680
681
682
683
684
685
686 private static Map<String, Object> getAllParametersForMultipartRequest(
687 HttpServletRequest request, MultipartRequestHandler multipartHandler) {
688
689 final Map<String, Object> parameters =
690 new HashMap<>(multipartHandler.getAllElements());
691
692 if (request instanceof MultipartRequestWrapper) {
693 request =
694 (HttpServletRequest) ((MultipartRequestWrapper) request)
695 .getRequest();
696
697 parameters.putAll(request.getParameterMap());
698 } else {
699 LOG.debug("Gathering multipart parameters for unwrapped request");
700 }
701
702 return parameters;
703 }
704
705
706
707
708
709
710
711
712
713
714 public static String printableURL(URL url) {
715 if (url.getHost() != null) {
716 return (url.toString());
717 }
718
719 String file = url.getFile();
720 String ref = url.getRef();
721
722 if (ref == null) {
723 return (file);
724 } else {
725 StringBuilder sb = new StringBuilder(file);
726
727 sb.append('#');
728 sb.append(ref);
729
730 return (sb.toString());
731 }
732 }
733
734
735
736
737
738
739
740
741
742
743
744
745 public static String actionURL(HttpServletRequest request,
746 ActionConfig action, String pattern) {
747 StringBuilder sb = new StringBuilder();
748
749 if (pattern.endsWith("/*")) {
750 sb.append(pattern.substring(0, pattern.length() - 2));
751 sb.append(action.getPath());
752 } else if (pattern.startsWith("*.")) {
753 ModuleConfig appConfig =
754 ModuleUtils.getInstance().getModuleConfig(request);
755
756 sb.append(appConfig.getPrefix());
757 sb.append(action.getPath());
758 sb.append(pattern.substring(1));
759 } else {
760 throw new IllegalArgumentException(pattern);
761 }
762
763 return sb.toString();
764 }
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821 public static String forwardURL(HttpServletRequest request,
822 ForwardConfig forward) {
823 return forwardURL(request, forward, null);
824 }
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873 public static String forwardURL(HttpServletRequest request,
874 ForwardConfig forward, ModuleConfig moduleConfig) {
875
876 if (moduleConfig == null) {
877 moduleConfig = ModuleUtils.getInstance().getModuleConfig(request);
878 }
879
880 String path = forward.getPath();
881
882
883 String prefix = moduleConfig.getPrefix();
884
885
886 if (forward.getModule() != null) {
887 prefix = forward.getModule();
888
889 if ("/".equals(prefix)) {
890 prefix = "";
891 }
892 }
893
894 StringBuilder sb = new StringBuilder();
895
896
897 String forwardPattern =
898 moduleConfig.getControllerConfig().getForwardPattern();
899
900 if (forwardPattern == null) {
901
902 sb.append(prefix);
903
904
905 if (!path.startsWith("/")) {
906 sb.append("/");
907 }
908
909 sb.append(path);
910 } else {
911 boolean dollar = false;
912
913 for (int i = 0; i < forwardPattern.length(); i++) {
914 char ch = forwardPattern.charAt(i);
915
916 if (dollar) {
917 switch (ch) {
918 case 'M':
919 sb.append(prefix);
920
921 break;
922
923 case 'P':
924
925
926 if (!path.startsWith("/")) {
927 sb.append("/");
928 }
929
930 sb.append(path);
931
932 break;
933
934 case '$':
935 sb.append('$');
936
937 break;
938
939 default:
940 ;
941 }
942
943 dollar = false;
944
945 continue;
946 } else if (ch == '$') {
947 dollar = true;
948 } else {
949 sb.append(ch);
950 }
951 }
952 }
953
954 return (sb.toString());
955 }
956
957
958
959
960
961
962
963
964
965 public static URL requestURL(HttpServletRequest request)
966 throws MalformedURLException {
967 StringBuilder url = requestToServerUriStringBuilder(request);
968
969 return (new URL(url.toString()));
970 }
971
972
973
974
975
976
977
978
979
980
981
982 public static URL serverURL(HttpServletRequest request)
983 throws MalformedURLException {
984 StringBuilder url = requestToServerStringBuilder(request);
985
986 return (new URL(url.toString()));
987 }
988
989
990
991
992
993
994
995
996
997
998
999 public static StringBuilder requestToServerUriStringBuilder(
1000 HttpServletRequest request) {
1001 StringBuilder serverUri =
1002 createServerUriStringBuilder(request.getScheme(),
1003 request.getServerName(), request.getServerPort(),
1004 request.getRequestURI());
1005
1006 return serverUri;
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 public static StringBuilder requestToServerStringBuilder(
1021 HttpServletRequest request) {
1022 return createServerStringBuilder(request.getScheme(),
1023 request.getServerName(), request.getServerPort());
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 public static StringBuilder createServerStringBuilder(String scheme,
1037 String server, int port) {
1038 StringBuilder url = new StringBuilder();
1039
1040 if (port < 0) {
1041 port = 80;
1042 }
1043
1044 url.append(scheme);
1045 url.append("://");
1046 url.append(server);
1047
1048 if ((scheme.equals("http") && (port != 80))
1049 || (scheme.equals("https") && (port != 443))) {
1050 url.append(':');
1051 url.append(port);
1052 }
1053
1054 return url;
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 public static StringBuilder createServerUriStringBuilder(String scheme,
1069 String server, int port, String uri) {
1070 StringBuilder serverUri = createServerStringBuilder(scheme, server, port);
1071
1072 serverUri.append(uri);
1073
1074 return serverUri;
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 public static String actionIdURL(ForwardConfig forward, HttpServletRequest request, ActionServlet servlet) {
1090 ModuleConfig moduleConfig = null;
1091 if (forward.getModule() != null) {
1092 String prefix = forward.getModule();
1093 moduleConfig = ModuleUtils.getInstance().getModuleConfig(prefix, servlet.getServletContext());
1094 } else {
1095 moduleConfig = ModuleUtils.getInstance().getModuleConfig(request);
1096 }
1097 return actionIdURL(forward.getPath(), moduleConfig, servlet);
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111 public static String actionIdURL(String originalPath, ModuleConfig moduleConfig, ActionServlet servlet) {
1112 if (originalPath.startsWith("http") || originalPath.startsWith("/")) {
1113 return null;
1114 }
1115
1116
1117
1118 String actionId = null;
1119 String qs = null;
1120 int qpos = originalPath.indexOf("?");
1121 if (qpos == -1) {
1122 actionId = originalPath;
1123 } else {
1124 actionId = originalPath.substring(0, qpos);
1125 qs = originalPath.substring(qpos);
1126 }
1127
1128
1129 ActionConfig actionConfig = moduleConfig.findActionConfigId(actionId);
1130 if (actionConfig == null) {
1131 LOG.debug("No actionId found for {}", actionId);
1132 return null;
1133 }
1134
1135 String path = actionConfig.getPath();
1136 String mapping = RequestUtils.getServletMapping(servlet);
1137 StringBuilder actionIdPath = new StringBuilder();
1138
1139
1140 if (mapping.startsWith("*")) {
1141 actionIdPath.append(path);
1142 actionIdPath.append(mapping.substring(1));
1143 } else if (mapping.startsWith("/")) {
1144 mapping = mapping.substring(0, mapping.length() - 1);
1145 if (mapping.endsWith("/") && path.startsWith("/")) {
1146 actionIdPath.append(mapping);
1147 actionIdPath.append(path.substring(1));
1148 } else {
1149 actionIdPath.append(mapping);
1150 actionIdPath.append(path);
1151 }
1152 } else {
1153 LOG.warn("Unknown servlet mapping pattern");
1154 actionIdPath.append(path);
1155 }
1156
1157
1158 if (qs != null) {
1159 actionIdPath.append(qs);
1160 }
1161
1162
1163 LOG.debug("{} unaliased to {}", originalPath, actionIdPath);
1164 return actionIdPath.toString();
1165 }
1166
1167
1168
1169
1170
1171
1172
1173
1174 public static boolean isRequestForwarded(HttpServletRequest request) {
1175 return (request.getAttribute("jakarta.servlet.forward.request_uri") != null);
1176 }
1177
1178
1179
1180
1181
1182
1183
1184
1185 public static boolean isRequestIncluded(HttpServletRequest request) {
1186 return (request.getAttribute("jakarta.servlet.include.request_uri") != null);
1187 }
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197 public static boolean isRequestChained(HttpServletRequest request) {
1198 return (request.getAttribute(Globals.CHAIN_KEY) != null);
1199 }
1200 }