Close Menu
  • Home
  • AI
  • Big Data
  • Cloud Computing
  • iOS Development
  • IoT
  • IT/ Cybersecurity
  • Tech
    • Nanotechnology
    • Green Technology
    • Apple
    • Software Development
    • Software Engineering

Subscribe to Updates

Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

    What's Hot

    This week in AI updates: GitHub Copilot SDK, Claude’s new constitution, and more (January 23, 2026)

    January 25, 2026

    Ambient-air power start-up secures £2m seed round funding

    January 25, 2026

    Today’s NYT Connections Hints, Answers for Jan. 25 #959

    January 25, 2026
    Facebook X (Twitter) Instagram
    Facebook X (Twitter) Instagram
    Big Tee Tech Hub
    • Home
    • AI
    • Big Data
    • Cloud Computing
    • iOS Development
    • IoT
    • IT/ Cybersecurity
    • Tech
      • Nanotechnology
      • Green Technology
      • Apple
      • Software Development
      • Software Engineering
    Big Tee Tech Hub
    Home»iOS Development»ios – Image file corrupted only when uploaded from Mobile Safari to Spring Boot on AWS EC2
    iOS Development

    ios – Image file corrupted only when uploaded from Mobile Safari to Spring Boot on AWS EC2

    big tee tech hubBy big tee tech hubJanuary 18, 2026004 Mins Read
    Share Facebook Twitter Pinterest Copy Link LinkedIn Tumblr Email Telegram WhatsApp
    Follow Us
    Google News Flipboard
    ios – Image file corrupted only when uploaded from Mobile Safari to Spring Boot on AWS EC2
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link


    I am facing a very strange and persistent image upload issue that occurs only in Mobile-Safari, and only when the server is running on AWS EC2.

    I have spent a significant amount of time debugging this, and at this point I am trying to determine whether this is a Safari + network/server environment interaction issue, rather than an application-level bug.

    Image upload works perfectly on:
    Chrome / Firefox (all platforms)
    Safari when the server is running on my local Windows 11 laptop

    Image upload fails (corrupted image) on:
    Safari (macOS / iOS)
    When the server is deployed on AWS EC2

    The image is already corrupted before any processing, directly at the Spring Boot controller level

    The corruption is visible as: Random horizontal lines Broken JPEG structure

    Different hex/binary content compared to the original file

    What I tried

    • Multiple upload methods tested

      multipart/form-data

      application/octet-stream

      XMLHttpRequest

      Sending raw File object without wrapping

      No manual Content-Type header

      No filename manipulation

    → Same result: Safari + EC2 = corrupted image

    Server specifications

    • Tested EC2 instances: t2.micro, t3.xlarge

      Same behavior regardless of CPU/memory

    *** I didn’t try it on the safari on the desktop. Only Mobile-Safari**

    corrupted JPEG

    normal hex dump
    corrupted hex dump

    @PostMapping(value = “/api/ckeditor/imageUpload”, consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE} )
    @ResponseBody
    public Map saveContentsImage(@RequestPart(value = “upload”, required = true) MultipartFile uploadFile, HttpServletRequest req, HttpServletResponse httpsResponse) {

        // ────────────────────────────────
        // 1️⃣ 기본 요청 정보 로깅
        // ────────────────────────────────
        String userAgent = req.getHeader("User-Agent");
        String contentType = uploadFile.getContentType();
        long fileSize = uploadFile.getSize();
    
        log.info("=== [UPLOAD DEBUG] CKEditor Image Upload Request ===");
        log.info("Request Method       : {}", req.getMethod());
        log.info("Client IP            : {}", req.getRemoteAddr());
        log.info("User-Agent           : {}", userAgent);
        log.info("Detected Browser     : {}", detectBrowser(userAgent));
        log.info("Content-Type (Part)  : {}", contentType);
        log.info("Content-Length (Hdr) : {}", req.getHeader("Content-Length"));
        log.info("Multipart Size       : {} bytes", fileSize);
        log.info("=====================================================");
    
        // Safari 업로드 이슈 발생 빈도가 높으므로 별도 디버그 경로에 저장
        boolean isSafari = userAgent != null && userAgent.contains("Safari") && !userAgent.contains("Chrome");
        
    
        // ================== [DEBUG] Save raw file at Controller level (User's requested method) ==================
        try {
            String projectRootPath = System.getProperty("user.dir");
            java.io.File debugDir = new java.io.File(projectRootPath, "tmp_debug");
    
            if (!debugDir.exists()) {
                debugDir.mkdirs();
            }
            // Sanitize the original filename to prevent path traversal issues
            String originalFilename = org.springframework.util.StringUtils.cleanPath(uploadFile.getOriginalFilename());
            // Differentiate the filename to indicate it's from the controller
            java.io.File rawDebugFile = new java.io.File(debugDir, "controller_raw_" + originalFilename);
    
            log.info("CONTROLLER DEBUG: Attempting to copy uploaded file to: {}", rawDebugFile.getAbsolutePath());
    
            // Use InputStream to copy the file, which does not move the original temp file.
            try (java.io.InputStream in = uploadFile.getInputStream();
                 java.io.OutputStream out = new java.io.FileOutputStream(rawDebugFile)) {
                in.transferTo(out);
            }
            log.info("CONTROLLER DEBUG: File successfully copied. Size: {} bytes", rawDebugFile.length());
    
        } catch (Exception e) {
            log.error("CONTROLLER DEBUG: Failed to copy debug file.", e);
        }
        // ================== [DEBUG] END ===================
    
        Long sessionCustomerId = SessionUtils.getSessionCustomerId(req);
        if (sessionCustomerId == null) {
            Map errorResponse = new HashMap<>();
            errorResponse.put("uploaded", 0);
            errorResponse.put("error", Map.of("message", "세션이 만료되었거나 로그인 상태가 아닙니다."));
            return errorResponse;
        }
    
        String customerId = sessionCustomerId.toString();
        String imageUrl = postUtils.saveContentsImage(uploadFile, customerId);
        Map response = new HashMap<>();
        response.put("uploaded", 1);
        response.put("fileName", uploadFile.getOriginalFilename());
        response.put("url", imageUrl);
        return response;
    }
    

    =============================================================================

    JS CODE

    const data = new FormData();

            // *** CSRF 토큰을 FormData에 직접 추가 ***
            const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
            const csrfParameterName = document.querySelector('meta[name="_csrf_parameter"]')?.getAttribute('content') || '_csrf';
    
            if (csrfToken) {
                console.log(csrfToken);
                data.append(csrfParameterName, csrfToken);
            }
    
           // const safeFile = new File([finalBlob], finalFileName, { type: finalMimeType });
            //const safeFile = new File([ab], finalFileName, { type: finalMimeType });
    
    
            // ✅ 2) File() 감싸지 말고 그대로 append
            //data.append('upload', finalBlob, finalFileName);
    
    
    
            // 원본 File 그대로 append (Blob 래핑 ❌)
            //data.append('upload', originalFile);
            // 원본 파일의 내용을 기반으로 Content-Type이 'application/octet-stream'으로 지정된 새 File 객체를 생성합니다.
            const octetStreamFile = new File([finalBlob], finalFileName, {
                type: 'application/octet-stream'
            });
            console.log(`[UploadAdapter] Content-Type을 'application/octet-stream'으로 강제 변환하여 업로드를 시도합니다.`
            );
            // 새로 생성된 File 객체를 FormData에 추가합니다.
            data.append('upload', octetStreamFile);
    
            //const cleanBlob = new Blob([originalFile], { type: originalFile.type });
            //data.set('upload', originalFile, toAsciiFilename(originalFile.name));
    
            //data.set('upload', originalFile,toAsciiFilename(originalFile.name));
            //data.append("upload", safeFile);
    
    
    
    
            // === fetch 업로드 (대체)  시작 ===
            const xhr = new XMLHttpRequest();
            xhr.open("POST", "/api/ckeditor/imageUpload", true);
            xhr.withCredentials = true;
    
            // Safari의 multipart/form-data 업로드 안정성을 높이기 위해 수동 boundary 지정 없이 자동 생성하게 둠
            // Content-Type을 직접 지정하지 않음 — 브라우저가 자동으로 생성하도록
            xhr.upload.onprogress = (event) => {
                if (event.lengthComputable) {
                    const percentCompleted = Math.round((event.loaded * 100) / event.total);
                    const progressBarFill = document.querySelector('.progressBarFill');
                    if (progressBarFill) {
                        progressBarFill.style.width = percentCompleted + '%';
                    }
                    const progressText = document.querySelector('.uploadingText');
                    if (progressText) {
                        progressText.textContent = `이미지 업로드 중... ${Math.round(event.loaded / 1024)}KB / ${Math.round(event.total / 1024)}KB (${percentCompleted}%)`;
                    }
                }
            };
    



    Source link

    AWS Boot corrupted EC2 File Image iOS Mobile Safari spring uploaded
    Follow on Google News Follow on Flipboard
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Copy Link
    tonirufai
    big tee tech hub
    • Website

    Related Posts

    ios – Why does my page scroll up when I tap on a button?

    January 25, 2026

    swift – iOS suspends app after BLE discovery even though I start Always-authorized location udpates

    January 24, 2026

    ios – ASAuthorizationControllerDelegate always returns .canceled for Face ID passcode fallback and failed attempts

    January 23, 2026
    Add A Comment
    Leave A Reply Cancel Reply

    Editors Picks

    This week in AI updates: GitHub Copilot SDK, Claude’s new constitution, and more (January 23, 2026)

    January 25, 2026

    Ambient-air power start-up secures £2m seed round funding

    January 25, 2026

    Today’s NYT Connections Hints, Answers for Jan. 25 #959

    January 25, 2026

    How Data-Driven Third-Party Logistics (3PL) Providers Are Transforming Modern Supply Chains

    January 25, 2026
    About Us
    About Us

    Welcome To big tee tech hub. Big tee tech hub is a Professional seo tools Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of seo tools, with a focus on dependability and tools. We’re working to turn our passion for seo tools into a booming online website. We hope you enjoy our seo tools as much as we enjoy offering them to you.

    Don't Miss!

    This week in AI updates: GitHub Copilot SDK, Claude’s new constitution, and more (January 23, 2026)

    January 25, 2026

    Ambient-air power start-up secures £2m seed round funding

    January 25, 2026

    Subscribe to Updates

    Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

      • About Us
      • Contact Us
      • Disclaimer
      • Privacy Policy
      • Terms and Conditions
      © 2026 bigteetechhub.All Right Reserved

      Type above and press Enter to search. Press Esc to cancel.