Image attachments with a colon character (':') do not load after upgrading Confluence
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Summary
After upgrading Confluence on Microsoft Windows, Confluence is unable to display images that have a colon character (':') in the attachment file name.
Environment
The following Confluence versions running on Microsoft Windows operating system are affected:
- Confluence 7.11.6
- Confluence 7.12.1 and later
Diagnosis
Attachments on a Confluence page containing a colon character (':') in their file name will display a broken image on the View page and on the Edit page:
The application log file atlassian-confluence.log
will display the following stack trace error:
NTFS ADS separator (':') in file name is forbidden.
2023-12-01 20:02:26,123 ERROR [http-nio-8090-exec-1] [[Standalone].[localhost].[/].[file-server]] log Servlet.service() for servlet [file-server] in context with path [] threw exception
java.lang.IllegalArgumentException: NTFS ADS separator (':') in file name is forbidden.
at org.apache.commons.io.FilenameUtils.indexOfExtension(FilenameUtils.java:955)
at org.apache.commons.io.FilenameUtils.getExtension(FilenameUtils.java:614)
at org.apache.commons.io.FilenameUtils.isExtension(FilenameUtils.java:1033)
at com.atlassian.confluence.util.AttachmentMimeTypeTranslator$CSVMimeTypeTranslationStrategy.handles(AttachmentMimeTypeTranslator.java:149)
at com.atlassian.confluence.util.AttachmentMimeTypeTranslator.resolveMimeType(AttachmentMimeTypeTranslator.java:182)
at com.atlassian.confluence.servlet.download.DefaultAttachmentSafeContentHeaderGuesser.computeAttachmentHeaders(DefaultAttachmentSafeContentHeaderGuesser.java:51)
at com.atlassian.confluence.servlet.download.AttachmentDownload.getHeadersForAttachment(AttachmentDownload.java:265)
at com.atlassian.confluence.servlet.download.AttachmentDownload.setHeadersForAttachment(AttachmentDownload.java:247)
at com.atlassian.confluence.servlet.download.AttachmentDownload.sendResponseHeaders(AttachmentDownload.java:155)
at com.atlassian.confluence.servlet.download.AttachmentDownload.getStreamForDownload(AttachmentDownload.java:109)
at com.atlassian.confluence.servlet.download.ServeAfterTransactionDownload$StreamResultCallback.doInTransaction(ServeAfterTransactionDownload.java:122)
at com.atlassian.confluence.servlet.download.ServeAfterTransactionDownload$StreamResultCallback.doInTransaction(ServeAfterTransactionDownload.java:105)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at com.atlassian.confluence.servlet.download.ServeAfterTransactionDownload.getStreamInTransaction(ServeAfterTransactionDownload.java:41)
at com.atlassian.confluence.servlet.download.ServeAfterTransactionDownload.serveFile(ServeAfterTransactionDownload.java:47)
...
Run the following SQL to confirm the number of attachments that contain a colon character (':'):
select count(*) from CONTENT where CONTENTTYPE = 'ATTACHMENT' and LOWERTITLE like '%:%';
Cause
Confluence versions that bundle Apache commons IO library newer than commons-io-2.6.jar enforces file names on Windows Operating Systems cannot contain the colon (':') character.
Resolution
We will need to perform the following directly in the Confluence database:
- Rename all attachment filenames in the
CONTENT
table to not contain the (':') character; and - Update all pages to point to the updated attachment filenames without the (':') character in the
BODYCONTENT
table.
The steps to perform the above are detailed in the below four stages.
Always back up your data before performing any modifications to the database. If possible, test any alter, insert, update, or delete SQL commands on a staging server first.
The following steps have been validated on Microsoft SQL Server database. If you are running another database engine, please work with your DBA to convert the below SQL to the equivalent SQL for your specific database engine.
Stage 1 - Shutdown Confluence
- Whilst Confluence is still running, navigate to Confluence Administration » General Configuration » Collaborative Editing » Disable Collaborative Editing (if Collaborative Editing is enabled)
- Shutdown Confluence
- If Confluence is running as a cluster, shut down Confluence on every node
- Take a backup of the Confluence database as the below steps will be making direct SQL updates to the Confluence database!
Stage 2 - SQL file preparation
This section can be performed on any Windows machine.
- Perl is required to run the below attached
fixfilename.pl
script file.- Download free Strawberry Perl for Microsoft Windows from https://strawberryperl.com/releases.html:
- The latest 64 bit portable edition is fine. e.g. v5.38.2.2 Portable 64-bit
- Extract to
C:\strawberry-perl-5.38.2.2-64bit-portable
- Download free Strawberry Perl for Microsoft Windows from https://strawberryperl.com/releases.html:
- Download this fixfilename.pl Perl script into
C:\strawberry-perl-5.38.2.2-64bit-portable
Work with your DBA to create a CSV text file named content.csv from the Confluence database from this SQL:
select CONTENTID, CONTENTTYPE, TITLE, LOWERTITLE FROM CONTENT where LOWERTITLE like '%:%' and CONTENTTYPE = 'ATTACHMENT';
Sample file contents:
CONTENTID,CONTENTTYPE,TITLE,LOWERTITLE 100123,ATTACHMENT,image2013-9-11 12:58:01.png,image2013-9-11 12:58:01.png 100124,ATTACHMENT,image2013-9-10 11:52:03.png,image2013-9-10 11:52:03.png 100125,ATTACHMENT,image2013-9-10 13:50:08.png,image2013-9-10 13:50:08.png 100126,ATTACHMENT,image2013-9-10 12:0:59.png,image2013-9-10 12:0:59.png ...
- Field delimiter must be a comma in the CSV file extract
Create a second CSV text file named bodycontent.csv from the Confluence database from this SQL:
select 'ROWSTART', BODYCONTENT.* from BODYCONTENT where BODY like '%ri:attachment ri:filename="%:%' OR BODY like '%<ri:url ri:value="%/download/attachments%';
Sample file contents:
ROWSTART,BODYCONTENTID,BODY,CONTENTID,BODYTYPEID ROWSTART,720899,"<p>......</p>",90045,2 ROWSTART,820200,"<p>......</p>",80012,2 ROWSTART,610305,"<p>... ...</p>",70008,2 ...
- Field delimiter must be a comma in the CSV file extract
- Save both the created content.csv and bodycontent.csv into the same folder where fixfilename.pl was saved to
Open a command prompt and change to the directory where fixfilename.pl, content.csv and bodycontent.csv are saved, e.g.
cd /d C:\strawberry-perl-5.38.2.2-64bit-portable
Run the
fixfilename.pl
script to see the script Usage screen:C:\strawberry-perl-5.38.2.2-64bit-portable> C:\strawberry-perl-5.38.2.2-64bit-portable\perl\bin\perl fixfilename.pl Usage : fixfilename.pl [-d mssql|postgres|mysql|oracle] <CONTENT_TABLE_CSV> <BODYCONTENT> Options: -d <db_type> mssql - generates SQL for Microsoft SQL Server (default) postgres - generates SQL for Postgres mysql - generates SQL for MySQL oracle - generates SQL for Oracle Description: This script will produce SQL UPDATES to clean up BODYCONTENT tables for attachments containing ':' character This script should only be run as per guidance from Atlassian Support team.
- Run the fixfilename.pl for your respective Confluence DB engine type against the content.csv and bodycontent.csv file set to generate the UPDATE SQL statements.
E.g. for Microsoft SQL Server database engine (default mode), simply run:
C:\strawberry-perl-5.38.2.2-64bit-portable\perl\bin\perl fixfilename.pl content.csv bodycontent.csv > generated_sql.txt
E.g. for an Oracle database engine, run with
-d oracle
option flag:C:\strawberry-perl-5.38.2.2-64bit-portable\perl\bin\perl fixfilename.pl -d oracle content.csv bodycontent.csv > generated_sql.txt
Sample generated_sql.txt output
reading 'content.csv'... done found 2120 unique ATTACHMENT file names with a ':' character reading 'bodycontent.csv'... done identified 28090 total SQL updates needed for embedded images identified 2306 total SQL updates needed for external images UPDATE BODYCONTENT set BODY=..... where BODYCONTENTID = X; UPDATE BODYCONTENT set BODY=..... where BODYCONTENTID = 100456; UPDATE BODYCONTENT set BODY=..... where BODYCONTENTID = 100789; ...
- We're most interested in the UPDATE BODYCONTENT... generated rows.
- The generated SQL statements are specific to your Confluence data set at the time the CSV files were generated.
- If the
fixfilename.pl
script throws an error, check that both CSV files are in the same format as the above sample CSV files. - If the
fixfilename.pl
script still fails to run successfully, please contact Atlassian Support.
Stage 3 - Performing the SQL update
Copy the generated
UPDATE BODYCONTENT...
SQL lines from the above generated_sql.txt and run against the Confluence database to update the BODYCONTENT table:... <Paste and run the generated SQL UPDATE statements>... e.g. update BODYCONTENT set BODY = cast(REPLACE(cast(BODY as....; update BODYCONTENT set BODY = cast(REPLACE(cast(BODY as....; ...
- Run this in chunks of roughly 10,000 rows
- Make sure no errors are returned
Now, run this SQL to update the CONTENT table in the Confluence database:
update CONTENT set TITLE = REPLACE(TITLE, ':', ''), LOWERTITLE= REPLACE(LOWERTITLE, ':', '') FROM CONTENT where CONTENTTYPE = 'ATTACHMENT' and LOWERTITLE like '%:%';
- Make sure no errors are returned
Empty out the Synchrony tables in the Confluence database:
truncate table "EVENTS"; truncate table "SECRETS"; truncate table "SNAPSHOTS";
Stage 4 - Start Confluence
- Backup these Confluence lucene index directories:
<confluence-local-home>/index
<confluence-local-home>/journal
- Delete the two Confluence lucene index directories:
<confluence-local-home>/index
<confluence-local-home>/journal
- Start Confluence
- Navigate to Confluence Administration » General Configuration » Collaborative Editing » Enable Collaborative Editing (if Collaborative Editing was disabled in Stage (1) / Step (1) above)
- Navigate to Confluence Administration » General Configuration » Content Indexing » Rebuild the indexes
- Check all pages now show image attachments correctly
- Feel free to delete
C:\strawberry-perl-5.38.2.2-64bit-portable
once all is confirmed okay in Confluence