Skip to content

Commit 8957e7d

Browse files
Encode pdf report output file name (#841)
* Encode pdf report output file name Issue:107307 * Fix encoding
1 parent 65bdabd commit 8957e7d

File tree

1 file changed

+114
-87
lines changed

1 file changed

+114
-87
lines changed

java/src/main/java/com/genexus/GXWebReport.java

Lines changed: 114 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,37 @@
44
import com.genexus.internet.HttpContext;
55
import com.genexus.reports.*;
66
import com.genexus.webpanels.GXWebProcedure;
7+
import org.apache.logging.log4j.Logger;
8+
9+
import java.io.UnsupportedEncodingException;
10+
import java.net.URLEncoder;
11+
import java.nio.charset.StandardCharsets;
12+
13+
public abstract class GXWebReport extends GXWebProcedure {
14+
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(GXWebReport.class);
715

8-
public abstract class GXWebReport extends GXWebProcedure
9-
{
1016
public static final int OUTPUT_RVIEWER = 1;
11-
public static final int OUTPUT_PDF = 2;
17+
public static final int OUTPUT_PDF = 2;
1218

1319
// Tiene que ser protected porque se pasa como par�metro en los reports
1420
protected GXReportMetadata reportMetadata;
1521
protected IReportHandler reportHandler;
1622

1723
protected int lineHeight;
18-
protected int Gx_line;
19-
protected int P_lines;
20-
protected int gxXPage;
21-
protected int gxYPage;
22-
protected int Gx_page;
23-
protected String Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask.
24+
protected int Gx_line;
25+
protected int P_lines;
26+
protected int gxXPage;
27+
protected int gxYPage;
28+
protected int Gx_page;
29+
protected String Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask.
2430
protected String filename;
2531
protected String filetype;
2632

27-
public GXWebReport(HttpContext httpContext)
28-
{
33+
public GXWebReport(HttpContext httpContext) {
2934
super(httpContext);
3035
}
3136

32-
protected void initState(ModelContext context, UserInformation ui)
33-
{
37+
protected void initState(ModelContext context, UserInformation ui) {
3438
super.initState(context, ui);
3539

3640
httpContext.setResponseBufferMode(HttpContext.ResponseBufferMode.ENABLED);
@@ -45,140 +49,163 @@ else if (implementation.equals("ITEXT8"))
4549
initValues();
4650
}
4751

48-
protected void preExecute()
49-
{
52+
protected void preExecute() {
5053
httpContext.setContentType("application/pdf");
5154
httpContext.setStream();
5255
((GXReportPDFCommons) reportHandler).setOutputStream(httpContext.getOutputStream());
5356
}
5457

55-
protected void setOutputFileName(String outputFileName){
58+
protected void setOutputFileName(String outputFileName) {
5659
filename = outputFileName;
5760
}
58-
protected void setOutputType(String outputType){
61+
protected void setOutputType(String outputType) {
5962
filetype = outputType.toLowerCase();
6063
}
61-
private void initValues()
62-
{
63-
Gx_line = 0;
64-
P_lines = 0;
65-
gxXPage = 0;
66-
gxYPage = 0;
67-
Gx_page = 0;
68-
Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask.
69-
lineHeight = 0;
64+
private void initValues() {
65+
Gx_line = 0;
66+
P_lines = 0;
67+
gxXPage = 0;
68+
gxYPage = 0;
69+
Gx_page = 0;
70+
Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask.
71+
lineHeight = 0;
7072
}
7173

72-
public void setPrinter(IReportHandler reportHandler)
73-
{
74+
public void setPrinter(IReportHandler reportHandler) {
7475
this.reportHandler = reportHandler;
7576
}
7677

77-
public IReportHandler getPrinter()
78-
{
78+
public IReportHandler getPrinter() {
7979
return reportHandler;
8080
}
8181

82-
protected void GxEndPage() throws ProcessInterruptedException
83-
{
84-
if (reportHandler != null)
82+
protected void GxEndPage() throws ProcessInterruptedException {
83+
if (reportHandler != null)
8584
reportHandler.GxEndPage();
8685
}
8786

88-
protected boolean initTextPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int nPaperLength, int nPaperWidth, int nGridX, int nGridY, int nPageLines)
89-
{
90-
int x[] = {gxXPage};
91-
int y[] = {gxYPage};
87+
protected boolean initTextPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int nPaperLength, int nPaperWidth, int nGridX, int nGridY, int nPageLines) {
88+
int x[] = {
89+
gxXPage
90+
};
91+
int y[] = {
92+
gxYPage
93+
};
9294

9395
getPrinter().GxRVSetLanguage(localUtil._language);
94-
boolean ret = getPrinter().GxPrTextInit(output, x, y, iniFile, form, printer, mode, nPaperLength, nPaperWidth, nGridX, nGridY, nPageLines);
96+
boolean ret = getPrinter().GxPrTextInit(output, x, y, iniFile, form, printer, mode, nPaperLength, nPaperWidth, nGridX, nGridY, nPageLines);
9597

9698
this.gxXPage = x[0];
9799
this.gxYPage = y[0];
98100

99101
return ret;
100102
}
101103

102-
protected boolean initPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int orientation, int pageSize, int pageLength, int pageWidth, int scale, int copies, int defSrc, int quality, int color, int duplex)
103-
{
104-
int x[] = {gxXPage};
105-
int y[] = {gxYPage};
106-
setResponseOuputFileName();
104+
protected boolean initPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int orientation, int pageSize, int pageLength, int pageWidth, int scale, int copies, int defSrc, int quality, int color, int duplex) {
105+
int x[] = {
106+
gxXPage
107+
};
108+
int y[] = {
109+
gxYPage
110+
};
111+
setResponseOutputFileName();
107112

108113
getPrinter().GxRVSetLanguage(localUtil._language);
109-
boolean ret = getPrinter().GxPrintInit(output, x, y, iniFile, form, printer, mode, orientation, pageSize, pageLength, pageWidth, scale, copies, defSrc, quality, color, duplex);
114+
boolean ret = getPrinter().GxPrintInit(output, x, y, iniFile, form, printer, mode, orientation, pageSize, pageLength, pageWidth, scale, copies, defSrc, quality, color, duplex);
110115

111116
this.gxXPage = x[0];
112117
this.gxYPage = y[0];
113118

114119
return ret;
115120
}
116121

117-
private void setResponseOuputFileName(){
118-
String outputFileName = filename!=null ? filename : getClass().getSimpleName();
119-
String outputFileType = filetype!=null ? "." + filetype.toLowerCase(): ".pdf";
120-
httpContext.getResponse().addHeader("content-disposition", "inline; filename=" + outputFileName + outputFileType);
121-
}
122-
123-
protected void endPrinter()
124-
{
122+
private void setResponseOutputFileName() {
123+
String outputFileName = (filename != null ? filename : getClass().getSimpleName());
124+
String outputFileType = (filetype != null ? "." + filetype.toLowerCase() : ".pdf");
125+
126+
try {
127+
String encodedFileName = URLEncoder.encode(outputFileName, "UTF-8").replace("+", "%20");
128+
boolean isAscii = StandardCharsets.US_ASCII.newEncoder().canEncode(outputFileName);
129+
String fallbackFileName = outputFileName;
130+
if (!isAscii) {
131+
fallbackFileName = outputFileName.replaceAll("[^\\p{ASCII}]", "");
132+
if (fallbackFileName.isEmpty()) {
133+
fallbackFileName = "download";
134+
}
135+
}
136+
String contentDispositionValue =
137+
"inline; filename=\"" + fallbackFileName + outputFileType + "\"; " +
138+
"filename*=UTF-8''" + encodedFileName + outputFileType;
139+
140+
httpContext.getResponse().addHeader("Content-Disposition", contentDispositionValue);
141+
} catch (UnsupportedEncodingException e) {
142+
httpContext.getResponse().addHeader("Content-Disposition", "inline; filename=\"download" + outputFileType + "\"");
143+
}
144+
}
145+
146+
/**
147+
* Returns an ASCII version of the filename.
148+
* Non-ASCII characters are replaced with underscore to ensure ASCII compliance.
149+
*/
150+
private String asciiFileName(String fileName) {
151+
StringBuilder asciiFileName = new StringBuilder();
152+
for (char character: fileName.toCharArray()) {
153+
if ((character <= 127)) {
154+
asciiFileName.append(character);
155+
} else {
156+
asciiFileName.append("_");
157+
}
158+
}
159+
return asciiFileName.toString();
160+
}
161+
162+
protected void endPrinter() {
125163
getPrinter().GxEndPrinter();
126164
}
127165

128-
protected int getOutputType()
129-
{
166+
protected int getOutputType() {
130167
return OUTPUT_RVIEWER;
131168
}
132169

133-
protected java.io.OutputStream getOutputStream()
134-
{
170+
protected java.io.OutputStream getOutputStream() {
135171
throw new RuntimeException("Output stream not set");
136172
}
137-
173+
138174
//M�todos para la implementaci�n de reportes din�micos
139-
protected void loadReportMetadata(String name)
140-
{
175+
protected void loadReportMetadata(String name) {
141176
reportMetadata = new GXReportMetadata(name, reportHandler);
142177
reportMetadata.load();
143178
}
144-
145-
protected int GxDrawDynamicGetPrintBlockHeight(int printBlock)
146-
{
179+
180+
protected int GxDrawDynamicGetPrintBlockHeight(int printBlock) {
147181
return reportMetadata.GxDrawGetPrintBlockHeight(printBlock);
148-
}
149-
150-
protected void GxDrawDynamicText(int printBlock, int controlId, int Gx_line)
151-
{
182+
}
183+
184+
protected void GxDrawDynamicText(int printBlock, int controlId, int Gx_line) {
152185
reportMetadata.GxDrawText(printBlock, controlId, Gx_line);
153186
}
154-
155-
protected void GxDrawDynamicText(int printBlock, int controlId, String value, int Gx_line)
156-
{
187+
188+
protected void GxDrawDynamicText(int printBlock, int controlId, String value, int Gx_line) {
157189
reportMetadata.GxDrawText(printBlock, controlId, Gx_line, value);
158190
}
159-
160-
protected void GxDrawDynamicLine(int printBlock, int controlId, int Gx_line)
161-
{
191+
192+
protected void GxDrawDynamicLine(int printBlock, int controlId, int Gx_line) {
162193
reportMetadata.GxDrawLine(printBlock, controlId, Gx_line);
163194
}
164-
165-
protected void GxDrawDynamicRect(int printBlock, int controlId, int Gx_line)
166-
{
195+
196+
protected void GxDrawDynamicRect(int printBlock, int controlId, int Gx_line) {
167197
reportMetadata.GxDrawRect(printBlock, controlId, Gx_line);
168-
}
169-
170-
protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int Gx_line)
171-
{
198+
}
199+
200+
protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int Gx_line) {
172201
reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, 0);
173202
}
174-
175-
protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int aspectRatio, int Gx_line)
176-
{
203+
204+
protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int aspectRatio, int Gx_line) {
177205
reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, aspectRatio);
178-
}
179-
180-
protected void cleanup( )
181-
{
206+
}
207+
208+
protected void cleanup() {
182209
super.cleanup();
183210
}
184-
}
211+
}

0 commit comments

Comments
 (0)